1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-04-25 19:51:51 +00:00

Multiple parallel instances of device::worker() possible

This commit is contained in:
Joerg Hoppe
2019-06-23 12:00:13 +02:00
parent 3952cb93b0
commit 4062386b97
36 changed files with 1620 additions and 100 deletions

View File

@@ -105,14 +105,15 @@ int cpu_dati(unsigned addr, unsigned *data) {
}
// background worker.
void cpu_c::worker(void) {
void cpu_c::worker(unsigned instance) {
UNUSED(instance) ; // only one
timeout_c timeout;
bool nxm;
unsigned pc = 0;
unsigned dr = 0760102;
unsigned opcode = 0;
(void) opcode;
while (!worker_terminate) {
while (!workers_terminate) {
// run full speed!
timeout.wait_us(1);

View File

@@ -57,7 +57,7 @@ public:
struct KA11 ka11; // Angelos CPU state
// background worker function
void worker(void) override;
void worker(unsigned instance) override;
// called by unibusadapter on emulated register access
void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control)

View File

@@ -182,9 +182,10 @@ void demo_io_c::gpio_set_output(unsigned output_index, unsigned value) {
// background worker.
// udpate LEDS, poll switches direct to register flipflops
void demo_io_c::worker(void) {
void demo_io_c::worker(unsigned instance) {
UNUSED(instance) ; // only one
timeout_c timeout;
while (!worker_terminate) {
while (!workers_terminate) {
timeout.wait_ms(100);
unsigned i;

View File

@@ -58,7 +58,7 @@ public:
false, "1 = hard wire Switches to LEDs, PDP-11 can not set LEDs");
// background worker function
void worker(void) override;
void worker(unsigned instance) override;
// called by unibusadapter on emulated register access
void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control)

View File

@@ -80,9 +80,10 @@ bool demo_regs_c::on_param_changed(parameter_c *param) {
// background worker.
// Just print a heart beat
void demo_regs_c::worker(void) {
void demo_regs_c::worker(unsigned instance) {
UNUSED(instance) ; // only one
timeout_c timeout;
while (!worker_terminate) {
while (!workers_terminate) {
timeout.wait_ms(1000);
cout << ".";
}

View File

@@ -43,7 +43,7 @@ public:
bool on_param_changed(parameter_c *param) override; // must implement
// background worker function
void worker(void) override;
void worker(unsigned instance) override;
// called by unibusadapter on emulated register access
void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control)

View File

@@ -0,0 +1,355 @@
/* DL11W.cpp: sample UNIBUS controller with SLU & LTC logic
Copyright (c) 2018, 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.
12-nov-2018 JH entered beta phase
20/12/2018 djrm copied to make slu device
14/01/2019 djrm adapted to use UART2 serial port
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <iostream>
#include <netdb.h>
#include <netinet/in.h>
#include "unibusadapter.hpp"
#include "unibusdevice.hpp" // definition of class device_c
#include "unibus.h"
#include "dl11w.hpp"
#include "gpios.hpp"
#include "rs232.hpp"
char buffer[BUFLEN + 1];
//-------------------------------------------------
slu_c::slu_c() :
unibusdevice_c() // super class constructor
{
//ip_host.value = IP_HOST; // not used
//ip_port.value = IP_PORT; // not used
// static config
name.value = "SLU";
type_name.value = "slu_c";
log_label = "slu";
set_default_bus_params(SLU_ADDR, SLU_VECTOR + 4, SLU_LEVEL); // base addr, intr-vector, intr level
// init parameters
// controller has some register
register_count = slu_idx_count;
reg_rcsr = &(this->registers[slu_idx_rcsr]); // @ base addr
strcpy(reg_rcsr->name, "RCSR"); // Receiver Status Register
reg_rcsr->active_on_dati = true;
reg_rcsr->active_on_dato = true;
reg_rcsr->reset_value = 0 & ! RCSR_RCVR_DONE;
reg_rcsr->writable_bits = 0xff;
reg_rbuf = &(this->registers[slu_idx_rbuf]); // @ base addr
strcpy(reg_rbuf->name, "RBUF"); // Receiver Buffer Register
reg_rbuf->active_on_dati = true; // no controller state change
reg_rbuf->active_on_dato = true;
reg_rbuf->reset_value = 0;
reg_rbuf->writable_bits = 0xff;
reg_xcsr = &(this->registers[slu_idx_xcsr]); // @ base addr
strcpy(reg_xcsr->name, "XCSR"); // Transmitter Status Register
reg_xcsr->active_on_dati = true;
reg_xcsr->active_on_dato = true;
reg_xcsr->reset_value = XCSR_XMIT_RDY; // set
reg_xcsr->writable_bits = 0xff;
reg_xbuf = &(this->registers[slu_idx_xbuf]); // @ base addr
strcpy(reg_xbuf->name, "XBUF"); //Transmitter Buffer Register
reg_xbuf->active_on_dati = true; // no controller state change
reg_xbuf->active_on_dato = true;
reg_xbuf->reset_value = 0;
reg_xbuf->writable_bits = 0xff;
// initialize serial format
baudrate.value = 9600;
mode.value = "8N1";
}
slu_c::~slu_c() {
}
bool slu_c::on_param_changed(parameter_c *param) {
if (param == &enabled) {
cport_nr = 2; /* UART2 */
if (enabled.new_value) {
// enable SLU: setup COM port
if (RS232_OpenComport(cport_nr, baudrate.value, mode.value.c_str())) {
ERROR("Can not open comport");
return false; // reject "enable"
}
// lock serial format settings
baudrate.readonly = true;
mode.readonly = true;
RS232_cputs(cport_nr, "Comport opened\n\r");
} else {
// disable SLU
RS232_CloseComport(cport_nr);
// lock serial format settings
baudrate.readonly = false;
mode.readonly = false;
}
}
return unibusdevice_c::on_param_changed(param); // more actions (for enable)
}
//--------------------------------------------
// background worker.
void slu_c::worker(void) {
timeout_c timeout;
char mychar;
int i, n;
while (!worker_terminate) {
timeout.wait_ms(SLU_MSRATE_MS);
/* read character from socket */
if (!(RCSR_RCVR_DONE & rcsr.value)) {
bzero(buffer, BUFLEN);
#if 1
if (slu_maint.value) {
n = 1;
buffer[0] = rbuf.value;
buffer[1] = 0;
} else
#endif
{
/* read serial data, if any */
n = RS232_PollComport(cport_nr, (unsigned char*) buffer, 1);
}
for (i = 0; i < n; i++) {
mychar = buffer[i];
// transmit chr to bus
rbuf.value = mychar;
set_register_dati_value(reg_rbuf, rbuf.value, __func__);
// signal data on bus ready to read
rcsr.value |= RCSR_RCVR_DONE;
set_register_dati_value(reg_rcsr, rcsr.value, __func__);
}
}
// transfer received character to socket
if (!(XCSR_XMIT_RDY & xcsr.value)) {
buffer[0] = get_register_dato_value(reg_xbuf);
RS232_SendByte(cport_nr, buffer[0]);
// signal data written
xcsr.value |= XCSR_XMIT_RDY;
set_register_dati_value(reg_xcsr, xcsr.value, __func__);
}
}
}
// process DATI/DATO access to one of my "active" registers
// !! called asynchronuously by PRU, with SSYN asserted and blocking UNIBUS.
// The time between PRU event and program flow into this callback
// is determined by ARM Linux context switch
//
// UNIBUS DATO cycles let dati_flipflops "flicker" outside of this proc:
// do not read back dati_flipflops.
void slu_c::on_after_register_access(unibusdevice_register_t *device_reg,
uint8_t unibus_control) {
if (unibus_control == UNIBUS_CONTROL_DATO) // bus write
set_register_dati_value(device_reg, device_reg->active_dato_flipflops, __func__);
switch (device_reg->index) {
case slu_idx_rcsr:
if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write
rcvr_interrupt_enable.value = !!(reg_rcsr->active_dato_flipflops
& (RCSR_RCVR_INT_ENB));
rdr_enable.value = !!(reg_rcsr->active_dato_flipflops & (RCSR_RDR_ENB));
}
break;
case slu_idx_xbuf:
if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write
// signal data has been written to bus
xcsr.value &= ~ XCSR_XMIT_RDY;
set_register_dati_value(reg_xcsr, xcsr.value, __func__);
// get value from bus write and put it into rx buffer
xbuf.value = reg_xbuf->active_dato_flipflops;
}
break;
case slu_idx_xcsr:
if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write
xmit_interrupt_enable.value = !!(reg_xcsr->active_dato_flipflops
& (XCSR_XMIT_INT_ENB));
slu_maint.value = !!(reg_xcsr->active_dato_flipflops & (XCSR_MAINT));
}
break;
case slu_idx_rbuf:
if (unibus_control == UNIBUS_CONTROL_DATI) { // bus read
// signal data has been read from bus
rcsr.value &= ~ RCSR_RCVR_DONE;
set_register_dati_value(reg_rcsr, rcsr.value, __func__);
}
break;
default:
break;
}
}
void slu_c::on_power_changed(void) {
if (power_down) { // power-on defaults
}
}
// UNIBUS INIT: clear all registers
void slu_c::on_init_changed(void) {
// write all registers to "reset-values"
if (init_asserted) {
reset_unibus_registers();
INFO("slu_c::on_init()");
}
}
//--------------------------------------------------------------------------------------------------
ltc_c::ltc_c() :
unibusdevice_c() // super class constructor
{
// static config
name.value = "LTC";
type_name.value = "ltc_c";
log_label = "ltc";
set_default_bus_params(LTC_ADDR, LTC_VECTOR, LTC_LEVEL); // base addr, intr-vector, intr level
// init parameters
// controller has some register
register_count = ltc_idx_count;
reg_lks = &(this->registers[ltc_idx_lks]); // @ base addr
strcpy(reg_lks->name, "LKS"); // Line Clock Status Register
reg_lks->active_on_dati = true; // no controller state change
reg_lks->active_on_dato = true;
reg_lks->reset_value = 0;
reg_lks->writable_bits = 0xff;
}
ltc_c::~ltc_c() {
}
bool ltc_c::on_param_changed(parameter_c *param) {
// no own parameter or "enable" logic here
return unibusdevice_c::on_param_changed(param); // more actions (for enable)
}
// background worker.
void ltc_c::worker(void) {
timeout_c timeout;
while (!worker_terminate) {
if (ltc_input.value) {
//should really wait for LTC input trailing edge here
timeout.wait_ms(10000);
} else
timeout.wait_ms(LTC_MSRATE_MS);
#if 0
printf("[%o",buslatches_getval[0]);
#endif
if (lke.value) {
lks.value |= LKS_INT_MON;
set_register_dati_value(reg_lks, lks.value, __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) {
if (unibus_control == UNIBUS_CONTROL_DATO) // bus write
set_register_dati_value(device_reg, device_reg->active_dato_flipflops, __func__);
switch (device_reg->index) {
case ltc_idx_lks:
if (unibus_control == UNIBUS_CONTROL_DATI) { // bus read
// signal data has been read from bus
lks.value &= ~ LKS_INT_MON;
set_register_dati_value(reg_lks, lks.value, __func__);
}
if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write
lks.value = reg_lks->active_dato_flipflops;
ltc_interrupt_enable.value = !!(reg_lks->active_dato_flipflops & (LKS_INT_ENB));
#if 0
if (reg_lks->active_dato_flipflops && 1)
{
interrupt();
//DEBUG("Interrupt!");
}
#endif
}
break;
default:
break;
}
}
void ltc_c::on_power_changed(void) {
if (power_down) { // power-on defaults
}
}
// UNIBUS INIT: clear all registers
void ltc_c::on_init_changed(void) {
// write all registers to "reset-values"
if (init_asserted) {
reset_unibus_registers();
INFO("ltc_c::on_init()");
}
}

View File

@@ -0,0 +1,188 @@
/* DL11W.hpp: sample UNIBUS controller with SLU & LTC logic
Copyright (c) 2018, 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.
12-nov-2018 JH entered beta phase
20/12/2018 djrm copied to make DL11-W device
*/
#ifndef _DL11W_HPP_
#define _DL11W_HPP_
#include <fstream>
using namespace std;
#include "utils.hpp"
#include "unibusdevice.hpp"
#include "parameter.hpp"
// socket console settings
//#define IP_PORT 5001
//#define IP_HOST "localhost"
// bus properties
#define DL11A 1
#if DL11A // console (teletype keyboard & printer)
#define SLU_ADDR 0777560
#define SLU_LEVEL 04
#define SLU_VECTOR 060
#elif DL11B // paper tape punch and reader
#define SLU_ADDR 0777550
#define SLU_LEVEL 04
#define SLU_VECTOR 070
#else // other serial device
#define SLU_ADDR 0776500
#define SLU_LEVEL 04
#define SLU_VECTOR 0300
#endif
//#define LTC_ADDR 0777546
// moved here to avoid clash with physical LTC installed
#define LTC_ADDR 0777544
#define LTC_LEVEL 06
#define LTC_VECTOR 0100
// global text buffer size for hostname etc
#define BUFLEN 32
// register bit definitions
#define RCSR_RCVR_ACT 004000
#define RCSR_RCVR_DONE 000200
#define RCSR_RCVR_INT_ENB 000100
#define RCSR_RDR_ENB 000001
#define RBUF_ERROR (1 << 15)
#define RBUF_OR_ERR (1 << 14)
#define RBUF_FR_ERR (1 << 13)
#define RBUF_P_ERR (1 << 12)
#define XCSR_XMIT_RDY 000200
#define XCSR_XMIT_INT_ENB 000100
#define XCSR_MAINT 000004
#define XCSR_BREAK 000001
#define LKS_INT_ENB 000100
#define LKS_INT_MON 000200
// background task sleep times
#define SLU_MSRATE_MS 10
#define LTC_MSRATE_MS 50
// unibus register indices
enum slu_reg_index {
slu_idx_rcsr = 0, slu_idx_rbuf, slu_idx_xcsr, slu_idx_xbuf, slu_idx_count,
};
enum ltc_reg_index {
ltc_idx_lks = 0, ltc_idx_count,
};
// ------------------------------------------ SLU -----------------------------
class slu_c: public unibusdevice_c {
private:
int cport_nr; // COM port handle for RS232 library
unibusdevice_register_t *reg_rcsr;
unibusdevice_register_t *reg_rbuf;
unibusdevice_register_t *reg_xcsr;
unibusdevice_register_t *reg_xbuf;
public:
slu_c();
~slu_c();
//parameter_string_c ip_host = parameter_string_c( this, "SLU socket IP host", "host", /*readonly*/ false, "ip hostname");
//parameter_unsigned_c ip_port = parameter_unsigned_c(this, "SLU socket IP port", "port", /*readonly*/ false, "", "%d", "ip port", 32, 10);
parameter_unsigned_c baudrate = parameter_unsigned_c(this, "baudrate", "b", /*readonly*/
false, "", "%d", "Baudrate: 110, 300, ... 115200", 115200, 10);
parameter_string_c mode = parameter_string_c(this, "mode", "m", /*readonly*/false,
"Mode: 8N1, 7E1, ... ");
// @David: duplicating device registers as parameters is not necessary ...
// they can be seen with "exam" anyhow.
parameter_unsigned_c rcsr = parameter_unsigned_c(this, "Receiver Status Register", "rcsr", /*readonly*/
false, "", "%o", "Internal state", 32, 8);
parameter_unsigned_c rbuf = parameter_unsigned_c(this, "Receiver Buffer Register", "rbuf", /*readonly*/
false, "", "%o", "Internal state", 32, 8);
parameter_unsigned_c xcsr = parameter_unsigned_c(this, "Transmitter Status Register",
"xcsr", /*readonly*/false, "", "%o", "Internal state", 32, 8);
parameter_unsigned_c xbuf = parameter_unsigned_c(this, "Transmitter Buffer Register",
"xbuf", /*readonly*/false, "", "%o", "Internal state", 32, 8);
parameter_bool_c xmit_interrupt_enable = parameter_bool_c(this, "XMIT interrupt enable",
"xie",/*readonly*/false, "1 = enable interrupt");
parameter_bool_c rcvr_interrupt_enable = parameter_bool_c(this, "RCVR interrupt enable",
"rie",/*readonly*/false, "1 = enable interrupt");
parameter_bool_c slu_maint = parameter_bool_c(this, "XCSR Maintenance", "maint",/*readonly*/
false, "1 = enable Maintenance mode enabled");
parameter_bool_c rdr_enable = parameter_bool_c(this, "RDR enable", "rdre",/*readonly*/false,
"1 = enable reader enable");
// background worker function
void worker(void) override;
// called by unibusadapter on emulated register access
void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control)
override;
bool on_param_changed(parameter_c *param) override; // must implement
void on_power_changed(void) override;
void on_init_changed(void) override;
};
//-------------------------------------------- LTC -------------------------------------
class ltc_c: public unibusdevice_c {
private:
unibusdevice_register_t *reg_lks;
public:
ltc_c();
~ltc_c();
parameter_unsigned_c lks = parameter_unsigned_c(this, "Line Clock Status Register", "lks", /*readonly*/
false, "", "%o", "Internal state", 32, 8);
parameter_bool_c lke = parameter_bool_c(this, "LKS timer enable", "lke",/*readonly*/false,
"1 = enable update of LKS_IMON by timer");
parameter_bool_c ltc_input = parameter_bool_c(this, "LTC input enable", "ltc",/*readonly*/
false, "1 = enable update of LKS_IMON by LTC Input");
parameter_bool_c ltc_interrupt_enable = parameter_bool_c(this, "LTC interrupt enable",
"lie",/*readonly*/false, "1 = enable interrupt");
// background worker function
void worker(void) override;
// called by unibusadapter on emulated register access
void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control)
override;
bool on_param_changed(parameter_c *param) override; // must implement
void on_power_changed(void) override;
void on_init_changed(void) override;
/*
void change_state(unsigned new_state);
void do_command_done(void);
*/
};
#endif

View File

@@ -27,6 +27,7 @@ using namespace std;
mscp_drive_c::mscp_drive_c(storagecontroller_c *controller, uint32_t driveNumber) :
storagedrive_c(controller), _useImageSize(false) {
set_workers_count(0) ; // needs no worker()
log_label = "MSCPD";
SetDriveType("RA81");
SetOffline();
@@ -304,10 +305,6 @@ bool mscp_drive_c::SetDriveType(const char* typeName) {
// worker():
// worker method for this drive. No work is necessary.
//
void mscp_drive_c::worker(void) {
// Nothing to do here at the moment. Thread will terminate immediately.
}
//
// on_power_changed():
// Handle power change notifications.

View File

@@ -48,8 +48,6 @@ public:
void on_power_changed(void) override;
void on_init_changed(void) override;
void worker(void) override;
public:
parameter_bool_c use_image_size = parameter_bool_c(this, "useimagesize", "uis", false,
"Determine unit size from image file instead of drive type");

View File

@@ -69,6 +69,7 @@ mscp_server::mscp_server(
polling_mutex(PTHREAD_MUTEX_INITIALIZER),
_credits(INIT_CREDITS)
{
set_workers_count(0) ; // no std worker()
name.value = "mscp_server" ;
type_name.value = "mscp_server_c" ;
log_label = "MSSVR" ;

View File

@@ -153,7 +153,6 @@ public:
public:
void on_power_changed(void) override {}
void on_init_changed(void) override {}
void worker(void) override {}
private:
uint32_t Abort(void);

View File

@@ -438,10 +438,11 @@ void paneldriver_c::i2c_sync_all_params() {
Query all used I2C chip register,
Update controls and parameters
*/
void paneldriver_c::worker(void) {
void paneldriver_c::worker(unsigned instance) {
UNUSED(instance) ; // only one
timeout_c timeout;
while (!worker_terminate) {
while (!workers_terminate) {
// poll in endless round
i2c_sync_all_params();
timeout.wait_ms(10);

View File

@@ -112,7 +112,7 @@ public:
void i2c_sync_all_params();
// background worker function
void worker(void) override;
void worker(unsigned instance) override;
void on_power_changed(void) override; // must implement
void on_init_changed(void) override; // must implement

View File

@@ -223,7 +223,8 @@ void rk05_c::drive_reset(void) {
// SCP change will be posted when the seek instigated above is completed.
}
void rk05_c::worker(void) {
void rk05_c::worker(unsigned instance) {
UNUSED(instance) ; // only one
timeout_c timeout;
while (true) {

View File

@@ -100,7 +100,7 @@ public:
void on_init_changed(void) override;
// background worker function
void worker(void) override;
void worker(unsigned instance) override;
};
#endif

View File

@@ -197,8 +197,9 @@ void rk11_c::dma_transfer(DMARequest &request)
// Background worker.
// Handle device operations.
void rk11_c::worker(void)
void rk11_c::worker(unsigned instance)
{
UNUSED(instance) ; // only one
worker_init_realtime_priority(rt_device);
@@ -207,7 +208,7 @@ void rk11_c::worker(void)
bool do_interrupt = true;
timeout_c timeout;
while (!worker_terminate)
while (!workers_terminate)
{
switch (_worker_state)
{

View File

@@ -155,7 +155,7 @@ public:
virtual ~rk11_c();
// background worker function
void worker(void) override;
void worker(unsigned instance) override;
// called by unibusadapter on emulated register access
void on_after_register_access(

View File

@@ -633,13 +633,14 @@ bool RL0102_c::cmd_write_next_sector_data(uint16_t *buffer, unsigned buffer_size
}
// thread
void RL0102_c::worker(void) {
void RL0102_c::worker(unsigned instance) {
UNUSED(instance) ; // only one
timeout_c timeout;
// set prio to RT, but less than RL11 controller
worker_init_realtime_priority(rt_device);
while (!worker_terminate) {
while (!workers_terminate) {
// worker_mutex.lock() ; // collision with cmd_seek() and on_xxx_changed()
// states have set error flags not in RL11 CSR: just update
update_status_word(drive_ready_line, drive_error_line);

View File

@@ -187,7 +187,7 @@ public:
void clear_error_register(void);
// background worker function
void worker(void) override;
void worker(unsigned instance) override;
};
#endif

View File

@@ -801,13 +801,14 @@ void RL11_c::state_readwrite() {
// thread
// excutes commands
void RL11_c::worker(void) {
void RL11_c::worker(unsigned instance) {
UNUSED(instance) ; // only one
assert(!pthread_mutex_lock(&on_after_register_access_mutex));
// set prio to RT, but less than unibus_adapter
worker_init_realtime_priority(rt_device);
while (!worker_terminate) {
while (!workers_terminate) {
/* process command state machine in parallel with
"active register" state changes
*/

View File

@@ -102,7 +102,7 @@ public:
void reset(void);
// background worker function
void worker(void) override;
void worker(unsigned instance) override;
RL0102_c *selected_drive(void);

View File

@@ -0,0 +1,823 @@
/*
***************************************************************************
*
* Author: Teunis van Beelen
*
* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Teunis van Beelen
*
* Email: teuniz@gmail.com
*
***************************************************************************
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
***************************************************************************
*/
/* Last revision: November 22, 2017 */
/* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */
#include "rs232.hpp"
#if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */
#define RS232_PORTNR 38
int Cport[RS232_PORTNR],
error;
struct termios new_port_settings,
old_port_settings[RS232_PORTNR];
const char *comports[RS232_PORTNR]={
// "/dev/ttyO0","/dev/ttyO1","/dev/ttyO2","/dev/ttyO3","/dev/ttyO4","/dev/ttyO5",
"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5",
"/dev/ttyS6","/dev/ttyS7","/dev/ttyS8","/dev/ttyS9","/dev/ttyS10","/dev/ttyS11",
"/dev/ttyS12","/dev/ttyS13","/dev/ttyS14","/dev/ttyS15","/dev/ttyUSB0",
"/dev/ttyUSB1","/dev/ttyUSB2","/dev/ttyUSB3","/dev/ttyUSB4","/dev/ttyUSB5",
"/dev/ttyAMA0","/dev/ttyAMA1","/dev/ttyACM0","/dev/ttyACM1",
"/dev/rfcomm0","/dev/rfcomm1","/dev/ircomm0","/dev/ircomm1",
"/dev/cuau0","/dev/cuau1","/dev/cuau2","/dev/cuau3",
"/dev/cuaU0","/dev/cuaU1","/dev/cuaU2","/dev/cuaU3"};
// returns 0 on success, else error
int RS232_OpenComport(int comport_number, int baudrate, const char *mode)
{
int baudr,
status;
if((comport_number>=RS232_PORTNR)||(comport_number<0))
{
printf("illegal comport number\n");
return(1);
}
switch(baudrate)
{
case 50 : baudr = B50;
break;
case 75 : baudr = B75;
break;
case 110 : baudr = B110;
break;
case 134 : baudr = B134;
break;
case 150 : baudr = B150;
break;
case 200 : baudr = B200;
break;
case 300 : baudr = B300;
break;
case 600 : baudr = B600;
break;
case 1200 : baudr = B1200;
break;
case 1800 : baudr = B1800;
break;
case 2400 : baudr = B2400;
break;
case 4800 : baudr = B4800;
break;
case 9600 : baudr = B9600;
break;
case 19200 : baudr = B19200;
break;
case 38400 : baudr = B38400;
break;
case 57600 : baudr = B57600;
break;
case 115200 : baudr = B115200;
break;
case 230400 : baudr = B230400;
break;
case 460800 : baudr = B460800;
break;
case 500000 : baudr = B500000;
break;
case 576000 : baudr = B576000;
break;
case 921600 : baudr = B921600;
break;
case 1000000 : baudr = B1000000;
break;
case 1152000 : baudr = B1152000;
break;
case 1500000 : baudr = B1500000;
break;
case 2000000 : baudr = B2000000;
break;
case 2500000 : baudr = B2500000;
break;
case 3000000 : baudr = B3000000;
break;
case 3500000 : baudr = B3500000;
break;
case 4000000 : baudr = B4000000;
break;
default : printf("invalid baudrate\n");
return(1);
break;
}
int cbits=CS8,
cpar=0,
ipar=IGNPAR,
bstop=0;
if(strlen(mode) != 3)
{
printf("invalid mode \"%s\"\n", mode);
return(1);
}
switch(mode[0])
{
case '8': cbits = CS8;
break;
case '7': cbits = CS7;
break;
case '6': cbits = CS6;
break;
case '5': cbits = CS5;
break;
default : printf("invalid number of data-bits '%c'\n", mode[0]);
return(1);
break;
}
switch(mode[1])
{
case 'N':
case 'n': cpar = 0;
ipar = IGNPAR;
break;
case 'E':
case 'e': cpar = PARENB;
ipar = INPCK;
break;
case 'O':
case 'o': cpar = (PARENB | PARODD);
ipar = INPCK;
break;
default : printf("invalid parity '%c'\n", mode[1]);
return(1);
break;
}
switch(mode[2])
{
case '1': bstop = 0;
break;
case '2': bstop = CSTOPB;
break;
default : printf("invalid number of stop bits '%c'\n", mode[2]);
return(1);
break;
}
/*
http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html
http://man7.org/linux/man-pages/man3/termios.3.html
*/
Cport[comport_number] = open(comports[comport_number], O_RDWR | O_NOCTTY | O_NDELAY);
if(Cport[comport_number]==-1)
{
perror("unable to open comport ");
return(1);
}
/* lock access so that another process can't also use the port */
if(flock(Cport[comport_number], LOCK_EX | LOCK_NB) != 0)
{
close(Cport[comport_number]);
perror("Another process has locked the comport.");
return(1);
}
error = tcgetattr(Cport[comport_number], old_port_settings + comport_number);
if(error==-1)
{
close(Cport[comport_number]);
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
perror("unable to read portsettings ");
return(1);
}
memset(&new_port_settings, 0, sizeof(new_port_settings)); /* clear the new struct */
new_port_settings.c_cflag = cbits | cpar | bstop | CLOCAL | CREAD;
new_port_settings.c_iflag = ipar;
new_port_settings.c_oflag = 0;
new_port_settings.c_lflag = 0;
new_port_settings.c_cc[VMIN] = 0; /* block untill n bytes are received */
new_port_settings.c_cc[VTIME] = 0; /* block untill a timer expires (n * 100 mSec.) */
cfsetispeed(&new_port_settings, baudr);
cfsetospeed(&new_port_settings, baudr);
error = tcsetattr(Cport[comport_number], TCSANOW, &new_port_settings);
if(error==-1)
{
tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
close(Cport[comport_number]);
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
perror("unable to adjust portsettings ");
return(1);
}
/* http://man7.org/linux/man-pages/man4/tty_ioctl.4.html */
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
{
tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
perror("unable to get portstatus");
return(1);
}
status |= TIOCM_DTR; /* turn on DTR */
status |= TIOCM_RTS; /* turn on RTS */
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
{
tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
perror("unable to set portstatus");
return(1);
}
return(0);
}
int RS232_PollComport(int comport_number, unsigned char *buf, int size)
{
int n;
n = read(Cport[comport_number], buf, size);
if(n < 0)
{
if(errno == EAGAIN) return 0;
}
return(n);
}
int RS232_SendByte(int comport_number, unsigned char byte)
{
int n = write(Cport[comport_number], &byte, 1);
if(n < 0)
{
if(errno == EAGAIN)
{
return 0;
}
else
{
return 1;
}
}
return(0);
}
int RS232_SendBuf(int comport_number, unsigned char *buf, int size)
{
int n = write(Cport[comport_number], buf, size);
if(n < 0)
{
if(errno == EAGAIN)
{
return 0;
}
else
{
return -1;
}
}
return(n);
}
void RS232_CloseComport(int comport_number)
{
int status;
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
{
perror("unable to get portstatus");
}
status &= ~TIOCM_DTR; /* turn off DTR */
status &= ~TIOCM_RTS; /* turn off RTS */
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
{
perror("unable to set portstatus");
}
tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
close(Cport[comport_number]);
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
}
/*
Constant Description
TIOCM_LE DSR (data set ready/line enable)
TIOCM_DTR DTR (data terminal ready)
TIOCM_RTS RTS (request to send)
TIOCM_ST Secondary TXD (transmit)
TIOCM_SR Secondary RXD (receive)
TIOCM_CTS CTS (clear to send)
TIOCM_CAR DCD (data carrier detect)
TIOCM_CD see TIOCM_CAR
TIOCM_RNG RNG (ring)
TIOCM_RI see TIOCM_RNG
TIOCM_DSR DSR (data set ready)
http://man7.org/linux/man-pages/man4/tty_ioctl.4.html
*/
int RS232_IsDCDEnabled(int comport_number)
{
int status;
ioctl(Cport[comport_number], TIOCMGET, &status);
if(status&TIOCM_CAR) return(1);
else return(0);
}
int RS232_IsCTSEnabled(int comport_number)
{
int status;
ioctl(Cport[comport_number], TIOCMGET, &status);
if(status&TIOCM_CTS) return(1);
else return(0);
}
int RS232_IsDSREnabled(int comport_number)
{
int status;
ioctl(Cport[comport_number], TIOCMGET, &status);
if(status&TIOCM_DSR) return(1);
else return(0);
}
void RS232_enableDTR(int comport_number)
{
int status;
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
{
perror("unable to get portstatus");
}
status |= TIOCM_DTR; /* turn on DTR */
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
{
perror("unable to set portstatus");
}
}
void RS232_disableDTR(int comport_number)
{
int status;
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
{
perror("unable to get portstatus");
}
status &= ~TIOCM_DTR; /* turn off DTR */
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
{
perror("unable to set portstatus");
}
}
void RS232_enableRTS(int comport_number)
{
int status;
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
{
perror("unable to get portstatus");
}
status |= TIOCM_RTS; /* turn on RTS */
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
{
perror("unable to set portstatus");
}
}
void RS232_disableRTS(int comport_number)
{
int status;
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
{
perror("unable to get portstatus");
}
status &= ~TIOCM_RTS; /* turn off RTS */
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
{
perror("unable to set portstatus");
}
}
void RS232_flushRX(int comport_number)
{
tcflush(Cport[comport_number], TCIFLUSH);
}
void RS232_flushTX(int comport_number)
{
tcflush(Cport[comport_number], TCOFLUSH);
}
void RS232_flushRXTX(int comport_number)
{
tcflush(Cport[comport_number], TCIOFLUSH);
}
#else /* windows */
#define RS232_PORTNR 16
HANDLE Cport[RS232_PORTNR];
char *comports[RS232_PORTNR]={"\\\\.\\COM1", "\\\\.\\COM2", "\\\\.\\COM3", "\\\\.\\COM4",
"\\\\.\\COM5", "\\\\.\\COM6", "\\\\.\\COM7", "\\\\.\\COM8",
"\\\\.\\COM9", "\\\\.\\COM10", "\\\\.\\COM11", "\\\\.\\COM12",
"\\\\.\\COM13", "\\\\.\\COM14", "\\\\.\\COM15", "\\\\.\\COM16"};
char mode_str[128];
int RS232_OpenComport(int comport_number, int baudrate, const char *mode)
{
if((comport_number>=RS232_PORTNR)||(comport_number<0))
{
printf("illegal comport number\n");
return(1);
}
switch(baudrate)
{
case 110 : strcpy(mode_str, "baud=110");
break;
case 300 : strcpy(mode_str, "baud=300");
break;
case 600 : strcpy(mode_str, "baud=600");
break;
case 1200 : strcpy(mode_str, "baud=1200");
break;
case 2400 : strcpy(mode_str, "baud=2400");
break;
case 4800 : strcpy(mode_str, "baud=4800");
break;
case 9600 : strcpy(mode_str, "baud=9600");
break;
case 19200 : strcpy(mode_str, "baud=19200");
break;
case 38400 : strcpy(mode_str, "baud=38400");
break;
case 57600 : strcpy(mode_str, "baud=57600");
break;
case 115200 : strcpy(mode_str, "baud=115200");
break;
case 128000 : strcpy(mode_str, "baud=128000");
break;
case 256000 : strcpy(mode_str, "baud=256000");
break;
case 500000 : strcpy(mode_str, "baud=500000");
break;
case 1000000 : strcpy(mode_str, "baud=1000000");
break;
default : printf("invalid baudrate\n");
return(1);
break;
}
if(strlen(mode) != 3)
{
printf("invalid mode \"%s\"\n", mode);
return(1);
}
switch(mode[0])
{
case '8': strcat(mode_str, " data=8");
break;
case '7': strcat(mode_str, " data=7");
break;
case '6': strcat(mode_str, " data=6");
break;
case '5': strcat(mode_str, " data=5");
break;
default : printf("invalid number of data-bits '%c'\n", mode[0]);
return(1);
break;
}
switch(mode[1])
{
case 'N':
case 'n': strcat(mode_str, " parity=n");
break;
case 'E':
case 'e': strcat(mode_str, " parity=e");
break;
case 'O':
case 'o': strcat(mode_str, " parity=o");
break;
default : printf("invalid parity '%c'\n", mode[1]);
return(1);
break;
}
switch(mode[2])
{
case '1': strcat(mode_str, " stop=1");
break;
case '2': strcat(mode_str, " stop=2");
break;
default : printf("invalid number of stop bits '%c'\n", mode[2]);
return(1);
break;
}
strcat(mode_str, " dtr=on rts=on");
/*
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363145%28v=vs.85%29.aspx
http://technet.microsoft.com/en-us/library/cc732236.aspx
*/
Cport[comport_number] = CreateFileA(comports[comport_number],
GENERIC_READ|GENERIC_WRITE,
0, /* no share */
NULL, /* no security */
OPEN_EXISTING,
0, /* no threads */
NULL); /* no templates */
if(Cport[comport_number]==INVALID_HANDLE_VALUE)
{
printf("unable to open comport\n");
return(1);
}
DCB port_settings;
memset(&port_settings, 0, sizeof(port_settings)); /* clear the new struct */
port_settings.DCBlength = sizeof(port_settings);
if(!BuildCommDCBA(mode_str, &port_settings))
{
printf("unable to set comport dcb settings\n");
CloseHandle(Cport[comport_number]);
return(1);
}
if(!SetCommState(Cport[comport_number], &port_settings))
{
printf("unable to set comport cfg settings\n");
CloseHandle(Cport[comport_number]);
return(1);
}
COMMTIMEOUTS Cptimeouts;
Cptimeouts.ReadIntervalTimeout = MAXDWORD;
Cptimeouts.ReadTotalTimeoutMultiplier = 0;
Cptimeouts.ReadTotalTimeoutConstant = 0;
Cptimeouts.WriteTotalTimeoutMultiplier = 0;
Cptimeouts.WriteTotalTimeoutConstant = 0;
if(!SetCommTimeouts(Cport[comport_number], &Cptimeouts))
{
printf("unable to set comport time-out settings\n");
CloseHandle(Cport[comport_number]);
return(1);
}
return(0);
}
int RS232_PollComport(int comport_number, unsigned char *buf, int size)
{
int n;
/* added the void pointer cast, otherwise gcc will complain about */
/* "warning: dereferencing type-punned pointer will break strict aliasing rules" */
ReadFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL);
return(n);
}
int RS232_SendByte(int comport_number, unsigned char byte)
{
int n;
WriteFile(Cport[comport_number], &byte, 1, (LPDWORD)((void *)&n), NULL);
if(n<0) return(1);
return(0);
}
int RS232_SendBuf(int comport_number, unsigned char *buf, int size)
{
int n;
if(WriteFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL))
{
return(n);
}
return(-1);
}
void RS232_CloseComport(int comport_number)
{
CloseHandle(Cport[comport_number]);
}
/*
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363258%28v=vs.85%29.aspx
*/
int RS232_IsDCDEnabled(int comport_number)
{
int status;
GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
if(status&MS_RLSD_ON) return(1);
else return(0);
}
int RS232_IsCTSEnabled(int comport_number)
{
int status;
GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
if(status&MS_CTS_ON) return(1);
else return(0);
}
int RS232_IsDSREnabled(int comport_number)
{
int status;
GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
if(status&MS_DSR_ON) return(1);
else return(0);
}
void RS232_enableDTR(int comport_number)
{
EscapeCommFunction(Cport[comport_number], SETDTR);
}
void RS232_disableDTR(int comport_number)
{
EscapeCommFunction(Cport[comport_number], CLRDTR);
}
void RS232_enableRTS(int comport_number)
{
EscapeCommFunction(Cport[comport_number], SETRTS);
}
void RS232_disableRTS(int comport_number)
{
EscapeCommFunction(Cport[comport_number], CLRRTS);
}
/*
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363428%28v=vs.85%29.aspx
*/
void RS232_flushRX(int comport_number)
{
PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT);
}
void RS232_flushTX(int comport_number)
{
PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT);
}
void RS232_flushRXTX(int comport_number)
{
PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT);
PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT);
}
#endif
void RS232_cputs(int comport_number, const char *text) /* sends a string to serial port */
{
while(*text != 0) RS232_SendByte(comport_number, *(text++));
}
/* return index in comports matching to device name or -1 if not found */
int RS232_GetPortnr(const char *devname)
{
int i;
char str[32];
#if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */
strcpy(str, "/dev/");
#else /* windows */
strcpy(str, "\\\\.\\");
#endif
strncat(str, devname, 16);
str[31] = 0;
for(i=0; i<RS232_PORTNR; i++)
{
if(!strcmp(comports[i], str))
{
return i;
}
}
return -1; /* device not found */
}

View File

@@ -0,0 +1,87 @@
/*
***************************************************************************
*
* Author: Teunis van Beelen
*
* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Teunis van Beelen
*
* Email: teuniz@gmail.com
*
***************************************************************************
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
***************************************************************************
*/
/* Last revision: August 5, 2017 */
/* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */
#ifndef rs232_INCLUDED
#define rs232_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <string.h>
#if defined(__linux__) || defined(__FreeBSD__)
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <sys/file.h>
#include <errno.h>
#else
#include <windows.h>
#endif
int RS232_OpenComport(int, int, const char *);
int RS232_PollComport(int, unsigned char *, int);
int RS232_SendByte(int, unsigned char);
int RS232_SendBuf(int, unsigned char *, int);
void RS232_CloseComport(int);
void RS232_cputs(int, const char *);
int RS232_IsDCDEnabled(int);
int RS232_IsCTSEnabled(int);
int RS232_IsDSREnabled(int);
void RS232_enableDTR(int);
void RS232_disableDTR(int);
void RS232_enableRTS(int);
void RS232_disableRTS(int);
void RS232_flushRX(int);
void RS232_flushTX(int);
void RS232_flushRXTX(int);
int RS232_GetPortnr(const char *);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -162,13 +162,15 @@ void uda_c::StateTransition(
// worker():
// Implements the initialization state machine.
//
void uda_c::worker(void)
void uda_c::worker(unsigned instance)
{
UNUSED(instance) ; // only one
worker_init_realtime_priority(rt_device);
timeout_c timeout;
while (!worker_terminate)
while (!workers_terminate)
{
//
// Wait to be awoken.

View File

@@ -63,7 +63,7 @@ public:
bool on_param_changed(parameter_c *param) override;
void worker(void) override;
void worker(unsigned instance) override;
void on_after_register_access(
unibusdevice_register_t *device_reg,