From e46b26b497984a07d2767e4ed5632f70d8edc009 Mon Sep 17 00:00:00 2001 From: Joerg Hoppe Date: Thu, 19 Sep 2019 10:56:43 +0200 Subject: [PATCH] DL11 / KW11 ZDLD and RSX11 OK --- 10.02_devices/2_src/dl11w.cpp | 200 +++++++++---------- 10.02_devices/2_src/dl11w.hpp | 10 +- 10.02_devices/2_src/rs232adapter.cpp | 108 ++++++---- 10.02_devices/2_src/rs232adapter.hpp | 33 +-- 10.02_devices/2_src/uda.cpp | 1 + 90_common/src/{inputline.c => inputline.cpp} | 50 +++-- 90_common/src/inputline.h | 36 ---- 90_common/src/inputline.hpp | 49 +++++ 8 files changed, 261 insertions(+), 226 deletions(-) rename 90_common/src/{inputline.c => inputline.cpp} (83%) delete mode 100644 90_common/src/inputline.h create mode 100644 90_common/src/inputline.hpp diff --git a/10.02_devices/2_src/dl11w.cpp b/10.02_devices/2_src/dl11w.cpp index 25f546b..c6d5ad7 100644 --- a/10.02_devices/2_src/dl11w.cpp +++ b/10.02_devices/2_src/dl11w.cpp @@ -346,13 +346,12 @@ void slu_c::on_init_changed(void) { // background worker. void slu_c::worker_rcv(void) { timeout_c timeout; - int n; - unsigned char buffer[BUFLEN + 1]; + rs232byte_t rcv_byte; // poll with frequency > baudrate, to see single bits //unsigned poll_periods_us = 1000000 / baudrate.value; - /* Receiver not time critical? UARTS are buffering + /* Receiver not time critical? UARTs are buffering So if thread is swapped out and back a burst of characters appear. -> Wait after each character for transfer time before polling RS232 again. @@ -361,7 +360,7 @@ void slu_c::worker_rcv(void) { // poll a bit faster to be ahead of char stream. // don't oversample: PDP-11 must process char in that time - // worker_init_realtime_priority(rt_device); + worker_init_realtime_priority(rt_device); while (!workers_terminate) { timeout.wait_us(poll_periods_us); @@ -371,33 +370,14 @@ void slu_c::worker_rcv(void) { // rcv_active: can only be set by polling the UART input GPIO pin? // at the moments, it is only sent on maintenance loopback xmt /* read serial data, if any */ - if (rs232adapter.byte_rcv_poll(buffer)) { + if (rs232adapter.rs232byte_rcv_poll(&rcv_byte)) { pthread_mutex_lock(&on_after_rcv_register_access_mutex); // signal changes atomic against UNIBUS accesses rcv_or_err = rcv_fr_err = rcv_p_err = 0; if (rcv_done) // not yet cleared? overrun! rcv_or_err = 1; - if (buffer[0] == 0xff) { - /* How to receive framing and parity errors: see termios(3) - If IGNPAR=0, PARMRK=1: error on received as \377 \0 - \377 received as \377 \377 - */ - n = rs232adapter.byte_rcv_poll(buffer); - assert(n); // next char after 0xff escape immediately available - - if (buffer[0] == 0) { // error flags - rcv_fr_err = rcv_p_err = 1; - n = rs232adapter.byte_rcv_poll(buffer); - assert(n); // next char after 0xff 0 seq is data" - rcv_buffer = buffer[0]; - } else if (buffer[0] == 0xff) { // enocoded 0xff - rcv_buffer = 0xff; - } else { - WARNING("Received 0xff seqeuence"); - rcv_buffer = buffer[0]; - } - } else - // received non escaped data byte - rcv_buffer = buffer[0]; + rcv_buffer = rcv_byte.c; + if (rcv_byte.format_error) + rcv_fr_err = rcv_p_err = 1; rcv_done = 1; rcv_active = 0; set_rbuf_dati_value(); @@ -413,7 +393,7 @@ void slu_c::worker_xmt(void) { assert(!pthread_mutex_lock(&on_after_register_access_mutex)); // Transmitter not time critical - // worker_init_realtime_priority(rt_device); + worker_init_realtime_priority(rt_device); while (!workers_terminate) { // 1. wait for xmt signal @@ -426,7 +406,10 @@ void slu_c::worker_xmt(void) { } // 2. transmit - rs232adapter.byte_xmt_send(xmt_buffer); + rs232byte_t xmt_byte; + xmt_byte.c = xmt_buffer; + xmt_byte.format_error = false; + rs232adapter.rs232byte_xmt_send(xmt_byte); xmt_ready = 0; set_xcsr_dati_value_and_INTR(); if (xmt_maint) { // loop back: simulate data byte coming in @@ -442,7 +425,7 @@ void slu_c::worker_xmt(void) { pthread_mutex_lock(&on_after_xmt_register_access_mutex); if (xmt_maint) // put sent byte into rcv buffer, receiver will poll it - rs232adapter.byte_loopback(xmt_buffer); + rs232adapter.rs232byte_loopback(xmt_byte); xmt_ready = 1; set_xcsr_dati_value_and_INTR(); @@ -478,9 +461,10 @@ ltc_c::ltc_c() : reg_lks = &(this->registers[0]); // @ base addr strcpy(reg_lks->name, "LKS"); // Line Clock Status Register reg_lks->active_on_dati = false; // status polled by CPU, not active + // reg_lks->active_on_dati = true; // debugging reg_lks->active_on_dato = true; - reg_lks->reset_value = 0; - reg_lks->writable_bits = LKS_INT_ENB; // interrupt enable + reg_lks->reset_value = LKS_INT_MON; + reg_lks->writable_bits = LKS_INT_ENB | LKS_INT_MON; // interrupt enable // init parameters frequency.value = 50; @@ -488,7 +472,7 @@ ltc_c::ltc_c() : // init controller state intr_enable = 0; - intr_monitor = 0; + line_clock_monitor = 0; } ltc_c::~ltc_c() { @@ -510,37 +494,23 @@ bool ltc_c::on_param_changed(parameter_c *param) { return unibusdevice_c::on_param_changed(param); // more actions (for enable) } -// calc static INTR condition level. -// Change of that condition calculated by intr_request_c.is_condition_raised() -// on raising edge. -bool ltc_c::get_intr_signal_level() { - return intr_monitor && intr_enable; -} - // set status register, and optionally generate INTR // intr_raise: if inactive->active transition of interrupt condition detected. -void ltc_c::set_lks_dati_value_and_INTR(void) { - uint16_t val = (intr_monitor ? LKS_INT_MON : 0) | (intr_enable ? LKS_INT_ENB : 0); - switch (intr_request.edge_detect(get_intr_signal_level())) { - case intr_request_c::INTERRUPT_EDGE_RAISING: +void ltc_c::set_lks_dati_value_and_INTR(bool do_intr) { + uint16_t val = (line_clock_monitor ? LKS_INT_MON : 0) | (intr_enable ? LKS_INT_ENB : 0); + if (do_intr) // set register atomically with INTR, if INTR not blocked unibusadapter->INTR(intr_request, reg_lks, val); - break; - case intr_request_c::INTERRUPT_EDGE_FALLING: - // BR6 is tied to monitor and enable, so raised INTRs may get canceled - unibusadapter->cancel_INTR(intr_request); + else + // set unrelated to INTR condition set_register_dati_value(reg_lks, val, __func__); - break; - default: - set_register_dati_value(reg_lks, val, __func__); - } } // process DATI/DATO access to one of my "active" registers void ltc_c::on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control) { pthread_mutex_lock(&on_after_register_access_mutex); - +// not necessary, not harmful? if (unibus_control == UNIBUS_CONTROL_DATO) // bus write set_register_dati_value(device_reg, device_reg->active_dato_flipflops, __func__); @@ -548,13 +518,19 @@ void ltc_c::on_after_register_access(unibusdevice_register_t *device_reg, case 0: // LKS if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write +//DEBUG("LKS wrDATO, val = 0%6o", reg_lks->active_dato_flipflops) ; intr_enable = !!(reg_lks->active_dato_flipflops & LKS_INT_ENB); - // schematic: INTERRUPT MONITOR can only be cleared + // schematic: LINE CLOCK MONITOR can only be cleared if ((reg_lks->active_dato_flipflops & LKS_INT_MON) == 0) - intr_monitor = 0 ; - set_lks_dati_value_and_INTR(); - } - break; + line_clock_monitor = 0; + if (!intr_enable || !line_clock_monitor) { + // BR6 is tied to monitor and enable, so raised INTRs may get canceled + unibusadapter->cancel_INTR(intr_request); + } + set_lks_dati_value_and_INTR(false); // INTR only by clock, not by LKs access + } else +//DEBUG("LKS DATI, control=%d, val = 0%6o = 0%6o", (int)unibus_control, reg_lks->active_dati_flipflops, device_reg->shared_register->value ) ; + break; default: break; @@ -574,11 +550,12 @@ void ltc_c::on_init_changed(void) { if (init_asserted) { reset_unibus_registers(); intr_enable = 0; - intr_monitor = 1; - + line_clock_monitor = 1; intr_request.edge_detect_reset(); - // INFO("ltc_c::on_init()"); - } + /7 but edge_detect not used + // initial condition is "not signaled" + // INFO("ltc_c::on_init()"); +} } /* background worker. @@ -587,59 +564,60 @@ void ltc_c::on_init_changed(void) { lost edges are compensated */ void ltc_c::worker(unsigned instance) { - UNUSED(instance); // only one - timeout_c global_time; - timeout_c timeout; - int64_t global_next_edge_ns; +UNUSED(instance); // only one +timeout_c global_time; +timeout_c timeout; +int64_t global_next_edge_ns; - INFO("KW11 time resolution is < %u us", - (unsigned )(global_time.get_resolution_ns() / 1000)); - global_time.start_ns(0); - global_next_edge_ns = global_time.elapsed_ns(); - uint64_t global_edge_count = 0; - while (!workers_terminate) { +// set prio to RT, but less than unibus_adapter +worker_init_realtime_priority(rt_device); - // signal egde period may change if 50/60 Hz is changed - uint64_t edge_period_ns = BILLION / (2 * frequency.value); - uint64_t wait_ns; - // overdue_ns: time which signal edge is too late - int64_t overdue_ns = (int64_t) global_time.elapsed_ns() - global_next_edge_ns; - // INFO does not work on 64 ints - // printf("elapsed [ms] =%u, overdue [us] =%u\n", (unsigned) global_time.elapsed_ms(), (unsigned) overdue_ns/1000) ; - // if overdue_ns positive, next signal edge should have occured - if (overdue_ns < 0) { - wait_ns = -overdue_ns; // wait until next edge time reached - } else { - // time for next signal edge reached - if (ltc_enable.value) { - global_edge_count++; - clock_signal = !clock_signal; // square wave - if (clock_signal) { - intr_monitor = 1; - pthread_mutex_lock(&on_after_register_access_mutex); - set_lks_dati_value_and_INTR(); - pthread_mutex_unlock(&on_after_register_access_mutex); - } - } else - // clock disconnected - clock_signal = 0; +INFO("KW11 time resolution is < %u us", (unsigned )(global_time.get_resolution_ns() / 1000)); +global_time.start_ns(0); +global_next_edge_ns = global_time.elapsed_ns(); +uint64_t global_edge_count = 0; +while (!workers_terminate) { + // signal egde period may change if 50/60 Hz is changed + uint64_t edge_period_ns = BILLION / (2 * frequency.value); + uint64_t wait_ns; + // overdue_ns: time which signal edge is too late + int64_t overdue_ns = (int64_t) global_time.elapsed_ns() - global_next_edge_ns; + // INFO does not work on 64 ints + // printf("elapsed [ms] =%u, overdue [us] =%u\n", (unsigned) global_time.elapsed_ms(), (unsigned) overdue_ns/1000) ; + // if overdue_ns positive, next signal edge should have occured + if (overdue_ns < 0) { + wait_ns = -overdue_ns; // wait until next edge time reached + } else { + // time for next signal edge reached + if (ltc_enable.value) { + global_edge_count++; + clock_signal = !clock_signal; // square wave + if (clock_signal) { + line_clock_monitor = 1; + pthread_mutex_lock(&on_after_register_access_mutex); + set_lks_dati_value_and_INTR(intr_enable); + pthread_mutex_unlock(&on_after_register_access_mutex); + } + } else + // clock disconnected + clock_signal = 0; - // time of next signal edge - global_next_edge_ns += edge_period_ns; - // overdue_ns now time which next signal edge is too late - overdue_ns -= edge_period_ns; + // time of next signal edge + global_next_edge_ns += edge_period_ns; + // overdue_ns now time which next signal edge is too late + overdue_ns -= edge_period_ns; - if (overdue_ns < 0) - // next edge now in future: wait exact - wait_ns = -overdue_ns; - else - // next edge still in past: - // wait shorter than signal edge period to keep up slowly - wait_ns = edge_period_ns / 2; - //if ((global_edge_count % 100) == 0) - // INFO("LTC: %u secs by edges", (unsigned)(global_edge_count/100) ) ; - } - timeout.wait_ns(wait_ns); + if (overdue_ns < 0) + // next edge now in future: wait exact + wait_ns = -overdue_ns; + else + // next edge still in past: + // wait shorter than signal edge period to keep up slowly + wait_ns = edge_period_ns / 2; + //if ((global_edge_count % 100) == 0) + // INFO("LTC: %u secs by edges", (unsigned)(global_edge_count/100) ) ; } + timeout.wait_ns(wait_ns); +} } diff --git a/10.02_devices/2_src/dl11w.hpp b/10.02_devices/2_src/dl11w.hpp index a680a8e..1176c39 100644 --- a/10.02_devices/2_src/dl11w.hpp +++ b/10.02_devices/2_src/dl11w.hpp @@ -37,7 +37,6 @@ using namespace std; #include "rs232.hpp" #include "rs232adapter.hpp" - // socket console settings //#define IP_PORT 5001 //#define IP_HOST "localhost" @@ -103,7 +102,7 @@ private: public: rs232adapter_c rs232adapter; /// stream router - private: +private: unibusdevice_register_t *reg_rcsr; unibusdevice_register_t *reg_rbuf; unibusdevice_register_t *reg_xcsr; @@ -192,12 +191,13 @@ private: // KW11 has one interrupt intr_request_c intr_request = intr_request_c(this); - bool clock_signal; // value of 50Hz square wave signal bool intr_enable; // interrupt enable, LKS bit 6 - bool intr_monitor ; // LKS bit 7 + bool line_clock_monitor; // LKS bit 7 + + bool clock_signal ; // square wave from pwower supply bool get_intr_signal_level(void); - void set_lks_dati_value_and_INTR(void); + void set_lks_dati_value_and_INTR(bool do_intr); public: diff --git a/10.02_devices/2_src/rs232adapter.cpp b/10.02_devices/2_src/rs232adapter.cpp index d545b2d..816a24e 100644 --- a/10.02_devices/2_src/rs232adapter.cpp +++ b/10.02_devices/2_src/rs232adapter.cpp @@ -37,8 +37,7 @@ . | +---> ringbuffer "PATTERN" . . | | . . | loopback | . - . rcv <----------|---< byte_loopback() . - . decoder | . + . rcv <-----------|---< char_loopback() . . buffer | . . | | . . +-----<--------|---< rs232.Poll()---< RxD "RS232" . @@ -66,7 +65,7 @@ rs232adapter_c::rs232adapter_c() { stream_rcv = NULL; stream_xmt = NULL; rcv_termios_error_encoding = false; - rcv_decoder.clear(); + rcvbuffer.clear(); pattern_stream_data[0] = 0; pattern[0] = 0; pattern_found = false; @@ -79,56 +78,92 @@ rs232adapter_c::rs232adapter_c() { // and 0xff 0xff for \ff // If IGNPAR=0, PARMRK=1: error on received as \377 \0 // \377 received as \377 \377 -bool rs232adapter_c::byte_rcv_poll(unsigned char *rcvchar) { +// result: true if data received +bool rs232adapter_c::rs232byte_rcv_poll(rs232byte_t *rcvbyte) { - pthread_mutex_lock(&mutex); bool result = false; // mixing input streams, with RS232 priority +// if (baudrate != 0 && !rcv_baudrate_delay.reached()) +// return result; // limit character rate + + pthread_mutex_lock(&mutex); + // loopback or part of previous 0xff,0xff sequence ? - int c = rcv_decoder.get(); - if (c != EOF) { - *rcvchar = c; - result = true; + result = !rcvbuffer.empty(); + if (result) { + *rcvbyte = rcvbuffer.front(); + rcvbuffer.pop_front(); } if (!result && rs232) { - // rs2323 must be programmed to generate 0xff 0xff sequences - result = rs232->PollComport(rcvchar, 1); + // rs232 must be programmed to generate 0xff 0xff sequences + /* How to receive framing and parity errors: see termios(3) + If IGNPAR=0, PARMRK=1: error on received as \377 \0 + \377 received as \377 \377 + */ + uint8_t c_raw; + rcvbyte->format_error = false; // default: no error info + int n = rs232->PollComport(&c_raw, 1); + if (rcv_termios_error_encoding && c_raw == 0xff) { + n = rs232->PollComport(&c_raw, 1); + assert(n); // next char after 0xff escape immediately available + + if (c_raw == 0) { // error flags + rcvbyte->format_error = true; + n = rs232->PollComport(&c_raw, 1); + assert(n); // next char after 0xff 0 seq is data" + rcvbyte->c = c_raw; + } else if (c_raw == 0xff) { // enocoded 0xff + rcvbyte->c = 0xff; + } else { + WARNING("Received 0xff sequence"); + rcvbyte->c = c_raw; + } + } else + // received non-escaped data byte + rcvbyte->c = c_raw; + result = (n > 0); } - if (stream_rcv && !result) { + if (!result && stream_rcv) { // deliver next char from stream delayed, with simulated baudrate - if (baudrate == 0 || rcv_baudrate_delay.reached()) { - int c = stream_rcv->get(); - if (c != EOF) { - *rcvchar = c; - if (rcv_termios_error_encoding && c == 0xff) { - // mark 2nd 0xff for output on next call - rcv_decoder.clear(); - rcv_decoder.put(0xff); - } - result = true; - if (baudrate != 0) - rcv_baudrate_delay.start_us(10 * MILLION / baudrate); // assume 10 bits per char - } +// if (baudrate == 0 || rcv_baudrate_delay.reached()) { + int c = stream_rcv->get(); + if (c != EOF) { + rcvbyte->c = c; + rcvbyte->format_error = false; + result = true; + if (baudrate != 0) + rcv_baudrate_delay.start_us(10 * MILLION / baudrate); // assume 10 bits per char } +// } } +// if (result && baudrate != 0) +// rcv_baudrate_delay.start_us(10 * MILLION / baudrate); // assume 10 bits per char +// rcv_baudrate_delay.start_us(MILLION); // 1 sec delay + pthread_mutex_unlock(&mutex); +// if (result) +// printf("< %c\n", *rcvbyte) ; + return result; } -void rs232adapter_c::byte_xmt_send(unsigned char xmtchar) { +void rs232adapter_c::rs232byte_xmt_send(rs232byte_t xmtbyte) { +// pthread_mutex_lock(&mutex); +// printf("%c >\n", xmtbyte) ; + if (rs232) - rs232->SendByte(xmtchar); + rs232->SendByte(xmtbyte.c); if (stream_xmt) - stream_xmt->put(xmtchar); + stream_xmt->put(xmtbyte.c); // pattern ring buffer unsigned n = strlen(pattern); if (n) { // put new chars at end of string unsigned m = strlen(pattern_stream_data); assert(m < pattern_max_len); - pattern_stream_data[m] = xmtchar; + pattern_stream_data[m] = xmtbyte.c; pattern_stream_data[m + 1] = 0; // only keep the last chars in buffer. while ((m = strlen(pattern_stream_data)) > n) @@ -137,21 +172,22 @@ void rs232adapter_c::byte_xmt_send(unsigned char xmtchar) { if (strstr(pattern_stream_data, pattern)) pattern_found = true; // user must clear } -// pattern_buffer. + pthread_mutex_unlock(&mutex); } -void rs232adapter_c::byte_loopback(unsigned char xmtchar) { +void rs232adapter_c::rs232byte_loopback(rs232byte_t xmtbyte) { + pthread_mutex_lock(&mutex); // not a queue, only single char (DL11 loopback) - rcv_decoder.clear(); - rcv_decoder.put(xmtchar); - if (rcv_termios_error_encoding && xmtchar == 0xff) - rcv_decoder.put(0xff); - // fill intermediate buffer with seqeunce to receive + // fill intermediate buffer with sequwnce to receive + rcvbuffer.push_back(xmtbyte); + pthread_mutex_unlock(&mutex); } void rs232adapter_c::set_pattern(char *pattern) { + pthread_mutex_lock(&mutex); strncpy(this->pattern, pattern, pattern_max_len); pattern_found = false; pattern_stream_data[0] = 0; + pthread_mutex_unlock(&mutex); } diff --git a/10.02_devices/2_src/rs232adapter.hpp b/10.02_devices/2_src/rs232adapter.hpp index e6c903d..e82f7ae 100644 --- a/10.02_devices/2_src/rs232adapter.hpp +++ b/10.02_devices/2_src/rs232adapter.hpp @@ -29,30 +29,39 @@ #include #include #include +#include #include "utils.hpp" #include "logsource.hpp" #include "rs232.hpp" +// a character with additional transmission status +typedef struct { + uint8_t c; // 5/6/7/8 bit character + // framing and parity errors combined + bool format_error; +} rs232byte_t; + class rs232adapter_c: public logsource_c { private: // for loopback and to decode 0xff to 0xff,0xff - std::stringstream rcv_decoder; + std::deque rcvbuffer; +// std::stringstream rcv_decoder; - // last sequence of xmt data for pattern matching - static const int pattern_max_len = 256 ; - char pattern[pattern_max_len+1]; // if != "", this is search for - char pattern_stream_data[pattern_max_len+1]; +// last sequence of xmt data for pattern matching + static const int pattern_max_len = 256; + char pattern[pattern_max_len + 1]; // if != "", this is search for + char pattern_stream_data[pattern_max_len + 1]; // deliver rcv chars delayed by this "baudrate" - timeout_c rcv_baudrate_delay ; + timeout_c rcv_baudrate_delay; public: rs232adapter_c(); - pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - unsigned baudrate ; // deliver rcv chars throttled by this "baudrate" + unsigned baudrate; // deliver rcv chars throttled by this "baudrate" // if true, an inject 0xff is delivered as 0xff,0xff. // this is compatible with termios(3) encoding of error flags @@ -64,9 +73,9 @@ public: rs232_c *rs232; // if assigned, routing to initialized RS232 port /*** BYTE interface ***/ - bool byte_rcv_poll(unsigned char *rcvchar); - void byte_xmt_send(unsigned char xmtchar); - void byte_loopback(unsigned char xmtchar); + bool rs232byte_rcv_poll(rs232byte_t *rcvbyte); + void rs232byte_xmt_send(rs232byte_t xmtbyte); + void rs232byte_loopback(rs232byte_t xmtbyte); /*** STREAM interface ***/ std::istream *stream_rcv; // users sets this to a stream which producess chars @@ -78,7 +87,7 @@ public: /*** PATTERN detection ***/ void set_pattern(char *pattern); - bool pattern_found; // switches ture on match, user must clear + bool pattern_found; // switches true on match, user must clear }; diff --git a/10.02_devices/2_src/uda.cpp b/10.02_devices/2_src/uda.cpp index 7030b30..dd882e1 100644 --- a/10.02_devices/2_src/uda.cpp +++ b/10.02_devices/2_src/uda.cpp @@ -20,6 +20,7 @@ #include #include +#include "gpios.hpp" // debug pin #include "unibus.h" #include "unibusadapter.hpp" #include "unibusdevice.hpp" diff --git a/90_common/src/inputline.c b/90_common/src/inputline.cpp similarity index 83% rename from 90_common/src/inputline.c rename to 90_common/src/inputline.cpp index d1cac51..6140dc0 100644 --- a/90_common/src/inputline.c +++ b/90_common/src/inputline.cpp @@ -1,6 +1,6 @@ -/* inputline.c: Advanced routines for user text input +/* inputline.cpp: Advanced routines for user text input - Copyright (c) 2012-2016, Joerg Hoppe + Copyright (c) 2012-2019, Joerg Hoppe j_hoppe@t-online.de, www.retrocmp.com Permission is hereby granted, free of charge, to any person obtaining a @@ -20,7 +20,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + 05-Sep-2019 JH C++, scripting 23-Feb-2012 JH created @@ -36,7 +36,7 @@ #include #include "kbhit.h" -#include "inputline.h" +#include "inputline.hpp" /* * get input from user @@ -66,14 +66,17 @@ */ -static FILE *inputline_file = NULL; - // reset input source and internal states -void inputline_init() { +void inputline_c::init() { // close file, if open - if (inputline_file) - fclose(inputline_file); - inputline_file = NULL; + if (file) + fclose(file); + file = NULL; +} + +bool inputline_c::openfile(char *filename) { + file = fopen(filename, "r"); + return (file != NULL); } // check, if line contains an internal "inputlien" command @@ -82,7 +85,7 @@ void inputline_init() { // .print // result: true = internal command processed // false = unkwown -static int inputline_internal(char *line) { +int inputline_c::internal(char *line) { if (!strncasecmp(line, ".wait", 5)) { struct timespec ts; unsigned millis; @@ -108,23 +111,23 @@ static int inputline_internal(char *line) { return 1; } else if (!strncasecmp(line, ".end", 3)) { // close input file - fclose(inputline_file); - inputline_file = NULL; + fclose(file); + file = NULL; return 1; } return 0; } -char *inputline(char *buffer, int buffer_size, const char *prompt) { +char *inputline_c::readline(char *buffer, int buffer_size, const char *prompt) { char *s; - if (inputline_file != NULL) { + if (file != NULL) { // read from file int ready = 0; - while (!ready && inputline_file != NULL) { + while (!ready && file != NULL) { /*** read line from text file ***/ - if (fgets(buffer, buffer_size, inputline_file) == NULL) { - fclose(inputline_file); - inputline_file = NULL; // file empty, or unreadable + if (fgets(buffer, buffer_size, file) == NULL) { + fclose(file); + file = NULL; // file empty, or unreadable ready = 1; } else { // remove terminating "\n" @@ -149,14 +152,14 @@ char *inputline(char *buffer, int buffer_size, const char *prompt) { // if empty line: repeat if (*buffer == 0) continue; - if (!inputline_internal(buffer)) { + if (!internal(buffer)) { printf("%s\n", buffer); ready = 1; } } } } - if (inputline_file == NULL) { + if (file == NULL) { /*** read interactive ***/ if (prompt && *prompt) printf("%s", prompt); @@ -169,8 +172,3 @@ char *inputline(char *buffer, int buffer_size, const char *prompt) { return buffer; } -bool inputline_fopen(char *filename) { - inputline_file = fopen(filename, "r"); - return (inputline_file != NULL); -} - diff --git a/90_common/src/inputline.h b/90_common/src/inputline.h deleted file mode 100644 index 26158bb..0000000 --- a/90_common/src/inputline.h +++ /dev/null @@ -1,36 +0,0 @@ -/* inputline.h: Advanced routines for user text input - - Copyright (c) 2012-2016, Joerg Hoppe - j_hoppe@t-online.de, www.retrocmp.com - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - 23-Feb-2012 JH created -*/ - -#ifndef INPUTLINE_H_ -#define INPUTLINE_H_ - -#include - -void inputline_init(void) ; -bool inputline_fopen(char *filename) ; -char *inputline(char *buffer, int buffer_size, const char *prompt) ; - -#endif /* INPUTLINE_H_ */ diff --git a/90_common/src/inputline.hpp b/90_common/src/inputline.hpp new file mode 100644 index 0000000..cf3d92e --- /dev/null +++ b/90_common/src/inputline.hpp @@ -0,0 +1,49 @@ +/* inputline.hpp: Advanced routines for user text input + + Copyright (c) 2012-2019, Joerg Hoppe + j_hoppe@t-online.de, www.retrocmp.com + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + JOERG HOPPE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + 05-Sep-2019 JH C++, scripting + 23-Feb-2012 JH created + */ + +#ifndef INPUTLINE_HPP_ +#define INPUTLINE_HPP_ + +#include +#include + +class inputline_c { +private: + FILE *file = NULL; + int internal(char *line); + +public: + inputline_c() { + init(); + } + void init(void); + + bool openfile(char *filename); + + char *readline(char *buffer, int buffer_size, const char *prompt); +}; + +#endif /* INPUTLINE_HPP_ */