mirror of
https://github.com/livingcomputermuseum/UniBone.git
synced 2026-04-03 04:19:01 +00:00
DL11 / KW11 ZDLD and RSX11 OK
This commit is contained in:
@@ -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 <char> received as \377 \0 <char>
|
||||
\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 <stray> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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 <char> received as \377 \0 <char>
|
||||
// \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 <char> received as \377 \0 <char>
|
||||
\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 <stray> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,30 +29,39 @@
|
||||
#include <ostream>
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <deque>
|
||||
#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<rs232byte_t> 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
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "gpios.hpp" // debug pin
|
||||
#include "unibus.h"
|
||||
#include "unibusadapter.hpp"
|
||||
#include "unibusdevice.hpp"
|
||||
|
||||
@@ -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 <time.h>
|
||||
|
||||
#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 <text>
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -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 <stdbool.h>
|
||||
|
||||
void inputline_init(void) ;
|
||||
bool inputline_fopen(char *filename) ;
|
||||
char *inputline(char *buffer, int buffer_size, const char *prompt) ;
|
||||
|
||||
#endif /* INPUTLINE_H_ */
|
||||
49
90_common/src/inputline.hpp
Normal file
49
90_common/src/inputline.hpp
Normal file
@@ -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 <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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_ */
|
||||
Reference in New Issue
Block a user