mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
ti99: New expansion card "TIPI".
This commit is contained in:
parent
098cf780a9
commit
f2ddee6df3
@ -3564,6 +3564,8 @@ if (BUSES["TI99"]~=null) then
|
||||
MAME_DIR .. "src/devices/bus/ti99/peb/ti_fdc.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99/peb/ti_rs232.cpp",
|
||||
MAME_DIR .. "src/devices/bus/ti99/peb/ti_rs232.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99/peb/tipi.cpp",
|
||||
MAME_DIR .. "src/devices/bus/ti99/peb/tipi.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99/peb/tn_ide.cpp",
|
||||
MAME_DIR .. "src/devices/bus/ti99/peb/tn_ide.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99/peb/tn_usbsm.cpp",
|
||||
|
@ -199,6 +199,7 @@ CRUCLK* 51||52 DBIN
|
||||
#include "pgram.h"
|
||||
#include "sidmaster.h"
|
||||
#include "scsicard.h"
|
||||
#include "tipi.h"
|
||||
|
||||
#define LOG_WARN (1U<<1) // Warnings
|
||||
#define LOG_CONFIG (1U<<2) // Configuration
|
||||
@ -503,6 +504,7 @@ void ti99_peribox_slot_standard(device_slot_interface &device)
|
||||
device.option_add("forti", TI99_FORTI);
|
||||
device.option_add("sidmaster", TI99_SIDMASTER);
|
||||
device.option_add("whtscsi", TI99_WHTSCSI);
|
||||
device.option_add("tipi", TI99_TIPI);
|
||||
}
|
||||
|
||||
void peribox_device::device_add_mconfig(machine_config &config)
|
||||
@ -549,6 +551,7 @@ void ti99_peribox_slot_evpc(device_slot_interface &device)
|
||||
device.option_add("forti", TI99_FORTI);
|
||||
device.option_add("sidmaster", TI99_SIDMASTER);
|
||||
device.option_add("whtscsi", TI99_WHTSCSI);
|
||||
device.option_add("tipi", TI99_TIPI);
|
||||
}
|
||||
|
||||
void peribox_ev_device::device_add_mconfig(machine_config &config)
|
||||
@ -606,6 +609,7 @@ void ti99_peribox_slot_geneve(device_slot_interface &device)
|
||||
device.option_add("forti", TI99_FORTI);
|
||||
device.option_add("sidmaster", TI99_SIDMASTER);
|
||||
device.option_add("whtscsi", TI99_WHTSCSI);
|
||||
device.option_add("tipi", TI99_TIPI);
|
||||
}
|
||||
|
||||
void peribox_gen_device::device_add_mconfig(machine_config &config)
|
||||
@ -663,6 +667,7 @@ void ti99_peribox_slot_sgcpu(device_slot_interface &device)
|
||||
device.option_add("forti", TI99_FORTI);
|
||||
device.option_add("sidmaster", TI99_SIDMASTER);
|
||||
device.option_add("whtscsi", TI99_WHTSCSI);
|
||||
device.option_add("tipi", TI99_TIPI);
|
||||
}
|
||||
|
||||
void peribox_sg_device::device_add_mconfig(machine_config &config)
|
||||
|
606
src/devices/bus/ti99/peb/tipi.cpp
Normal file
606
src/devices/bus/ti99/peb/tipi.cpp
Normal file
@ -0,0 +1,606 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Michael Zapf
|
||||
/****************************************************************************
|
||||
|
||||
TIPI adapter card
|
||||
designed and realized by Matthew Splett (aka jedimatt42), Peter and others
|
||||
|
||||
The TIPI system (pronouced "tipee") is an expansion for the TI-99/4A and
|
||||
other computers of this family. It consists of a Raspberry Pi computer
|
||||
attached to an adapter card that fits into the PEB (Peripheral Expansion
|
||||
Box) or to the console side connector.
|
||||
|
||||
The adapter card provides an interface between the TI system and the
|
||||
Raspberry Pi, in particular for exchanging files. More than that, features
|
||||
of the Raspberry like network connectivity, may be offered to the TI
|
||||
system.
|
||||
|
||||
The general concept is that there is a set of memory-mapped ports between
|
||||
the TI and the Raspberry Pi.
|
||||
|
||||
0x5ff9 (RCIN): PI Control Signal (input from RPi)
|
||||
0x5ffb (RDIN): PI Data (input)
|
||||
0x5ffd (TCOUT): TI Control Signal (output to RPi)
|
||||
0x5fff (TDOUT): TI Data (output)
|
||||
|
||||
CRU map
|
||||
-------
|
||||
1x00: Activate the card and its ROM (x=0...f)
|
||||
1x02: Send RESET to Raspberry Pi
|
||||
|
||||
|
||||
Raspberry connection
|
||||
--------------------
|
||||
The good thing in terms of emulation is that the Raspberry Pi is completely
|
||||
outside of the emulation. It allows for connecting via a WebSocket, which
|
||||
is especially provided for emulators. In the real machine, the Raspberry Pi
|
||||
gets the data from the adapter card.
|
||||
|
||||
It is recommended to run a virtual Raspberry Pi as a QEMU image. An image
|
||||
is available on the TIPI website.
|
||||
|
||||
The connection is specified by -conn rpi.<hostname>[:<port>],
|
||||
like "-conn rpi.localhost" or "-conn rpi.some.host.net"
|
||||
|
||||
This will create a file in the current directory of that name, which is
|
||||
a side effect of the MAME image handling. The port default is 9901.
|
||||
|
||||
|
||||
Mouse support
|
||||
-------------
|
||||
The websocket server accepts messages for mouse movements and button actions
|
||||
from the mouse input of the connected emulator. However, in MAME, mouse
|
||||
input is only available if there is a proper mouse device, like the busmouse
|
||||
or the Mechatronics mouse. Hence, we cannot send any mouse input to the
|
||||
Raspberry without one of these mice connected.
|
||||
|
||||
However, if a mouse is connected to the real or virtual Raspberry Pi,
|
||||
the mouse operations can be polled from the Raspberry in the
|
||||
intended way.
|
||||
|
||||
Michael Zapf
|
||||
March 20222
|
||||
|
||||
References
|
||||
|
||||
[1] TIPI description on Github: https://github.com/jedimatt42/tipi
|
||||
|
||||
TODO: Add ASYNC mode
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "tipi.h"
|
||||
|
||||
#define LOG_WARN (1U<<1)
|
||||
#define LOG_EPROM (1U<<2)
|
||||
#define LOG_CRU (1U<<3)
|
||||
#define LOG_PORTS (1U<<4)
|
||||
#define LOG_CONFIG (1U<<5)
|
||||
#define LOG_RPI (1U<<6)
|
||||
|
||||
#define VERBOSE ( LOG_GENERAL | LOG_WARN | LOG_CONFIG )
|
||||
#define RASPI "rpi"
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(TI99_TIPI, bus::ti99::peb::tipi_card_device, "ti99_tipi", "TIPI card")
|
||||
DEFINE_DEVICE_TYPE(TI99_TIPI_RPI, bus::ti99::peb::tipi_attached_device, "ti99_tipi_atttached", "Connection to external device")
|
||||
|
||||
namespace bus::ti99::peb {
|
||||
|
||||
tipi_card_device::tipi_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
device_t(mconfig, TI99_TIPI, tag, owner, clock),
|
||||
device_ti99_peribox_card_interface(mconfig, *this),
|
||||
m_rpi(*this, RASPI),
|
||||
m_address(0),
|
||||
m_dsr(false),
|
||||
m_portaccess(false)
|
||||
{
|
||||
}
|
||||
|
||||
void tipi_card_device::setaddress_dbin(offs_t offset, int state)
|
||||
{
|
||||
if (machine().side_effects_disabled()) return;
|
||||
m_address = offset;
|
||||
m_dsr = false;
|
||||
m_portaccess = false;
|
||||
|
||||
if (in_dsr_space(offset, true) && m_selected)
|
||||
{
|
||||
m_portaccess = ((offset & 0x1ff8)==0x1ff8);
|
||||
m_dsr = !m_portaccess;
|
||||
}
|
||||
}
|
||||
|
||||
void tipi_card_device::readz(offs_t offset, uint8_t *value)
|
||||
{
|
||||
if (machine().side_effects_disabled())
|
||||
{
|
||||
debug_read(offset, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dsr)
|
||||
{
|
||||
// Lines A0-A12 directly connected to the EPROM (chip pin order)
|
||||
// Lines A13-A15 connected to PLD
|
||||
int base = 0;
|
||||
uint8_t* rom = &m_eprom[base | (m_address & 0x1fff)];
|
||||
*value = *rom;
|
||||
|
||||
if (WORD_ALIGNED(m_address))
|
||||
{
|
||||
// Do logging by 16 bit words, as we typically have instructions in
|
||||
// the eprom
|
||||
uint16_t val = (*rom << 8) | (*(rom+1));
|
||||
LOGMASKED(LOG_EPROM, "DSR: %04x -> %04x\n", m_address & 0xffff, val);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_portaccess)
|
||||
{
|
||||
if ((m_address & 5)==1)
|
||||
{
|
||||
int val = 0;
|
||||
if (m_address & 2)
|
||||
{
|
||||
val = m_rd;
|
||||
LOGMASKED(LOG_PORTS, "RDIN -> %02x\n", val);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = m_rc;
|
||||
LOGMASKED(LOG_PORTS, "RCIN -> %02x\n", val);
|
||||
}
|
||||
*value = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tipi_card_device::write(offs_t offset, uint8_t data)
|
||||
{
|
||||
if (machine().side_effects_disabled())
|
||||
{
|
||||
debug_write(offset, data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dsr)
|
||||
{
|
||||
LOGMASKED(LOG_WARN, "Writing to DSR space: %04x <- %02x\n", m_address & 0xffff, data);
|
||||
}
|
||||
|
||||
if (m_portaccess)
|
||||
{
|
||||
if (m_address & 1)
|
||||
{
|
||||
if (m_address & 2)
|
||||
{
|
||||
LOGMASKED(LOG_PORTS, "TDOUT <- %02x\n", data);
|
||||
set_td(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_PORTS, "TCOUT <- %02x\n", data);
|
||||
set_tc(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tipi_card_device::set_td(u8 data)
|
||||
{
|
||||
m_td = data;
|
||||
}
|
||||
|
||||
void tipi_card_device::set_tc(u8 data)
|
||||
{
|
||||
if (m_tc != data)
|
||||
{
|
||||
m_tc = data;
|
||||
process_message();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Debugger access.
|
||||
*/
|
||||
void tipi_card_device::debug_read(offs_t offset, uint8_t* value)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
Debugger access.
|
||||
*/
|
||||
void tipi_card_device::debug_write(offs_t offset, uint8_t data)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
CRU read access
|
||||
*/
|
||||
void tipi_card_device::crureadz(offs_t offset, uint8_t *value)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
CRU write access.
|
||||
*/
|
||||
void tipi_card_device::cruwrite(offs_t offset, uint8_t data)
|
||||
{
|
||||
if ((offset & 0xff00) == m_cru_base)
|
||||
{
|
||||
int bit = (offset >> 1) & 0x1f;
|
||||
switch (bit)
|
||||
{
|
||||
case 0: // card activation
|
||||
LOGMASKED(LOG_CRU, "DSR %s\n", (data!=0)? "on" : "off");
|
||||
m_selected = (data != 0);
|
||||
break;
|
||||
case 1:
|
||||
LOGMASKED(LOG_CRU, "CRU Bit 1 %s\n", (data!=0)? "on" : "off");
|
||||
if (data != 0) send("RESET");
|
||||
break;
|
||||
default:
|
||||
LOGMASKED(LOG_CRU, "Unknown CRU Bit %d\n", bit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tipi_card_device::send(const char* message)
|
||||
{
|
||||
*m_send_stream << message;
|
||||
m_wsclient->send(m_send_stream);
|
||||
}
|
||||
|
||||
void tipi_card_device::send(u8* message, int len)
|
||||
{
|
||||
for (int i=0; i < len; i++)
|
||||
{
|
||||
LOGMASKED(LOG_RPI, "Sending byte %02x\n", message[i]);
|
||||
*m_send_stream << message[i];
|
||||
}
|
||||
m_wsclient->send(m_send_stream, nullptr, 130); // binary (10000010)
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
TSWB = 0x02,
|
||||
TSRB = 0x06,
|
||||
TSRSET = 0xf1
|
||||
};
|
||||
|
||||
/*
|
||||
Messages from server:
|
||||
"RD=xxx"
|
||||
"RC=xxx"
|
||||
|
||||
processMessage occurs for each incoming message
|
||||
and each time that TC has been changed
|
||||
|
||||
Write a message to RPi:
|
||||
|
||||
for i=-2..(n-1)
|
||||
Write byte to TD
|
||||
Write (02 | (i & 1)) to TC
|
||||
|
||||
Byte sequence: len1 len2 m0 m1 m2 m3 ... m(n-1), where n = len1<<8 | len2;
|
||||
|
||||
Message will be written to RPi when complete
|
||||
|
||||
|
||||
Read a message from RPi:
|
||||
|
||||
n = message.length
|
||||
n = n1<<8 | n2
|
||||
|
||||
Write 06 to TC
|
||||
n1 = Read byte from TD
|
||||
Write 07 to TC
|
||||
n2 = Read byte from TD
|
||||
|
||||
for i=0..(n-1)
|
||||
Write (06 | (i & 1)) to TC
|
||||
Read byte from TD
|
||||
|
||||
*/
|
||||
void tipi_card_device::process_message()
|
||||
{
|
||||
if (m_tc == TSRSET) // Reset command
|
||||
{
|
||||
m_rpimessage = nullptr;
|
||||
m_msgindex = -2;
|
||||
m_rc = m_tc;
|
||||
send("SYNC");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_tc & 0xfe) == TSWB) // 02 and 03: write byte (LSB as strobe)
|
||||
{
|
||||
if (m_msgindex == -2)
|
||||
m_msglength = m_td << 8;
|
||||
else
|
||||
{
|
||||
if (m_msgindex == -1)
|
||||
{
|
||||
m_msglength |= m_td;
|
||||
m_rpimessage = std::make_unique<u8[]>(m_msglength);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_rpimessage != nullptr)
|
||||
m_rpimessage[m_msgindex] = m_td;
|
||||
}
|
||||
}
|
||||
|
||||
m_msgindex++;
|
||||
if (m_msgindex == m_msglength)
|
||||
{
|
||||
// Message is complete - transmit it
|
||||
LOGMASKED(LOG_RPI, "Sending message, length %d\n", m_msglength);
|
||||
send(m_rpimessage.get(), m_msglength);
|
||||
m_rpimessage = nullptr;
|
||||
}
|
||||
m_rc = m_tc; // Auto-acknowledge
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_tc & 0xfe) == TSRB) // 06 and 07: read byte (LSB as strobe)
|
||||
{
|
||||
if (m_rpimessage != nullptr)
|
||||
{
|
||||
if (m_msgindex == -2)
|
||||
m_rd = (m_msglength >> 8)& 0xff;
|
||||
else
|
||||
{
|
||||
if (m_msgindex == -1)
|
||||
m_rd = m_msglength & 0xff;
|
||||
else
|
||||
{
|
||||
m_rd = m_rpimessage[m_msgindex];
|
||||
}
|
||||
}
|
||||
m_msgindex++;
|
||||
m_rc = m_tc; // Auto-acknowledge
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Syntax for connecting is
|
||||
-conn rpi.<host>[:<port>]
|
||||
|
||||
Default for port is 9901.
|
||||
*/
|
||||
void tipi_card_device::open_websocket()
|
||||
{
|
||||
if (m_rpi->exists())
|
||||
{
|
||||
// We are just interested in the file name
|
||||
// Cannot call it "socket.xxx" because this will make sdlsocket open
|
||||
// the connection
|
||||
std::string sconn(m_rpi->filename());
|
||||
int pos = sconn.find("rpi.");
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
std::string shost(sconn.substr(pos + 4));
|
||||
if (shost.find(":")==-1)
|
||||
shost += ":9901";
|
||||
|
||||
shost += "/tipi";
|
||||
|
||||
LOGMASKED(LOG_CONFIG, "Connection to Raspberry Pi at %s\n", shost.c_str());
|
||||
|
||||
m_wsclient = std::make_unique<webpp::ws_client>(shost);
|
||||
webpp::ws_client* wsc = m_wsclient.get();
|
||||
wsc->on_open =
|
||||
[wsc,this]()
|
||||
{ websocket_opened(); };
|
||||
|
||||
wsc->on_message =
|
||||
[wsc,this](std::shared_ptr<webpp::ws_client::Message> message)
|
||||
{ websocket_incoming(message); };
|
||||
|
||||
wsc->on_close =
|
||||
[wsc,this](int i, const std::string& msg)
|
||||
{ websocket_closed(i, msg); };
|
||||
|
||||
wsc->on_error =
|
||||
[wsc,this](const std::error_code& code)
|
||||
{ websocket_error(code); };
|
||||
|
||||
m_send_stream = std::make_shared<webpp::ws_client::SendStream>();
|
||||
|
||||
asio::thread listener([this]()
|
||||
{ m_wsclient->start(); });
|
||||
}
|
||||
else
|
||||
fatalerror("Invalid TIPI connection address. Syntax: -conn rpi.<host>[:<port>]\n");
|
||||
}
|
||||
else
|
||||
LOGMASKED(LOG_CONFIG, "No Raspberry Pi connected\n");
|
||||
}
|
||||
|
||||
void tipi_card_device::websocket_opened()
|
||||
{
|
||||
LOGMASKED(LOG_RPI, "Opening connection\n");
|
||||
m_connected = true;
|
||||
}
|
||||
|
||||
void tipi_card_device::websocket_incoming(std::shared_ptr<webpp::ws_client::Message> message)
|
||||
{
|
||||
switch (message->fin_rsv_opcode & 0x0f)
|
||||
{
|
||||
case 1:
|
||||
// Text message is "RD=xxx" or "RC=xxx" with xxx=decimal number
|
||||
LOGMASKED(LOG_RPI, "Got text message: %s\n", message->string());
|
||||
if (message->string().find("RD=")==0)
|
||||
{
|
||||
m_rd = std::stoi(message->string().substr(3));
|
||||
}
|
||||
if (message->string().find("RC=")==0)
|
||||
{
|
||||
m_rc = std::stoi(message->string().substr(3));
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
LOGMASKED(LOG_RPI, "Got binary message, length %d\n", message->size());
|
||||
m_rpimessage = std::make_unique<u8[]>(message->size());
|
||||
for (int i=0; i < message->size(); i++)
|
||||
m_rpimessage[i] = (u8)message->get();
|
||||
|
||||
m_msglength = message->size();
|
||||
m_msgindex = -2;
|
||||
process_message();
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_RPI, "Got unknown message\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void tipi_card_device::websocket_error(const std::error_code& code)
|
||||
{
|
||||
if (code.value() == std::make_error_code(std::errc::connection_reset).value())
|
||||
{
|
||||
m_wsclient->stop();
|
||||
if (m_attempts > 0)
|
||||
{
|
||||
m_attempts--;
|
||||
LOGMASKED(LOG_CONFIG, "Error, connection reset. Retrying.\n");
|
||||
m_restart_timer->adjust(attotime::from_msec(1000));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_CONFIG, "Connection is reset on setup several times; giving up\n");
|
||||
m_connected = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_RPI, "Got error: %s (%d)\n", code.message().c_str(), code.value());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Restart the websocket connection
|
||||
*/
|
||||
void tipi_card_device::device_timer(emu_timer &timer, device_timer_id id, int param)
|
||||
{
|
||||
open_websocket();
|
||||
}
|
||||
|
||||
|
||||
void tipi_card_device::websocket_closed(int i, const std::string& msg)
|
||||
{
|
||||
LOGMASKED(LOG_RPI, "Closing connection\n");
|
||||
// Open it again after 2 secs
|
||||
m_wsclient->stop();
|
||||
m_restart_timer->adjust(attotime::from_msec(3000));
|
||||
}
|
||||
|
||||
void tipi_card_device::device_start()
|
||||
{
|
||||
m_eprom = memregion(TI99_DSRROM)->base();
|
||||
save_item(NAME(m_address));
|
||||
save_item(NAME(m_dsr));
|
||||
save_item(NAME(m_portaccess));
|
||||
save_item(NAME(m_msgindex));
|
||||
save_item(NAME(m_msglength));
|
||||
save_item(NAME(m_attempts));
|
||||
save_item(NAME(m_connected));
|
||||
save_item(NAME(m_tc));
|
||||
save_item(NAME(m_td));
|
||||
save_item(NAME(m_rc));
|
||||
save_item(NAME(m_rd));
|
||||
|
||||
m_restart_timer = timer_alloc(0);
|
||||
m_attempts = 5;
|
||||
}
|
||||
|
||||
void tipi_card_device::device_reset()
|
||||
{
|
||||
m_cru_base = (ioport("SW1")->read()) << 8;
|
||||
m_address = 0;
|
||||
m_dsr = false;
|
||||
m_portaccess = false;
|
||||
open_websocket();
|
||||
m_connected = false;
|
||||
}
|
||||
|
||||
/*
|
||||
The CRU address base for the card.
|
||||
*/
|
||||
INPUT_PORTS_START( tipi )
|
||||
PORT_START("SW1")
|
||||
PORT_DIPNAME(0x1f, 0x10, "TIPI card CRU base")
|
||||
PORT_DIPSETTING(0x10, "1000") // Default setting
|
||||
PORT_DIPSETTING(0x11, "1100")
|
||||
PORT_DIPSETTING(0x12, "1200")
|
||||
PORT_DIPSETTING(0x13, "1300")
|
||||
PORT_DIPSETTING(0x14, "1400")
|
||||
PORT_DIPSETTING(0x15, "1500")
|
||||
PORT_DIPSETTING(0x16, "1600")
|
||||
PORT_DIPSETTING(0x17, "1700")
|
||||
PORT_DIPSETTING(0x18, "1800")
|
||||
PORT_DIPSETTING(0x19, "1900")
|
||||
PORT_DIPSETTING(0x1a, "1a00")
|
||||
PORT_DIPSETTING(0x1b, "1b00")
|
||||
PORT_DIPSETTING(0x1c, "1c00")
|
||||
PORT_DIPSETTING(0x1d, "1d00")
|
||||
PORT_DIPSETTING(0x1e, "1e00")
|
||||
PORT_DIPSETTING(0x1f, "1f00")
|
||||
INPUT_PORTS_END
|
||||
|
||||
void tipi_card_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
TI99_TIPI_RPI(config, m_rpi, 0);
|
||||
}
|
||||
|
||||
ROM_START( tipi )
|
||||
ROM_REGION(0x8000, TI99_DSRROM, 0)
|
||||
ROM_LOAD("tipidsr.u2", 0x0000, 0x8000, CRC(a54e65af) SHA1(f930e4b079a5b6b24dc20f262e9c599d2051b6be))
|
||||
ROM_END
|
||||
|
||||
|
||||
const tiny_rom_entry *tipi_card_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( tipi );
|
||||
}
|
||||
|
||||
ioport_constructor tipi_card_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME( tipi );
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Connection to the external device, a Raspberry PI */
|
||||
|
||||
tipi_attached_device::tipi_attached_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, TI99_TIPI_RPI, tag, owner, clock),
|
||||
device_image_interface(mconfig, *this)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize connection
|
||||
*/
|
||||
image_init_result tipi_attached_device::call_load()
|
||||
{
|
||||
return image_init_result::PASS; // OK
|
||||
}
|
||||
|
||||
void tipi_attached_device::call_unload()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} // end namespace bus::ti99::peb
|
116
src/devices/bus/ti99/peb/tipi.h
Normal file
116
src/devices/bus/ti99/peb/tipi.h
Normal file
@ -0,0 +1,116 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Michael Zapf
|
||||
/****************************************************************************
|
||||
|
||||
TIPI adapter card for the Peripheral Expansion Box
|
||||
See tipi.cpp for documentation
|
||||
|
||||
Michael Zapf
|
||||
February 2022
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MAME_BUS_TI99_PEB_TIPI_H
|
||||
#define MAME_BUS_TI99_PEB_TIPI_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "peribox.h"
|
||||
#include "client_ws.hpp"
|
||||
|
||||
namespace bus::ti99::peb {
|
||||
|
||||
class tipi_attached_device;
|
||||
|
||||
class tipi_card_device : public device_t, public device_ti99_peribox_card_interface
|
||||
{
|
||||
|
||||
public:
|
||||
tipi_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
void readz(offs_t offset, uint8_t *value) override;
|
||||
void write(offs_t offset, uint8_t data) override;
|
||||
void setaddress_dbin(offs_t offset, int state) override;
|
||||
|
||||
void crureadz(offs_t offset, uint8_t *value) override;
|
||||
void cruwrite(offs_t offset, uint8_t data) override;
|
||||
|
||||
private:
|
||||
void device_start() override;
|
||||
void device_reset() override;
|
||||
ioport_constructor device_input_ports() const override;
|
||||
const tiny_rom_entry *device_rom_region() const override;
|
||||
void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
void debug_read(offs_t offset, uint8_t* value);
|
||||
void debug_write(offs_t offset, uint8_t data);
|
||||
|
||||
void websocket_opened();
|
||||
void websocket_incoming(std::shared_ptr<webpp::ws_client::Message> message);
|
||||
void websocket_error(const std::error_code& code);
|
||||
void websocket_closed(int i, const std::string& msg);
|
||||
void open_websocket();
|
||||
void device_timer(emu_timer &timer, device_timer_id id, int param);
|
||||
|
||||
void send(const char* message);
|
||||
void send(u8* message, int len);
|
||||
void process_message();
|
||||
void set_td(u8 data);
|
||||
void set_tc(u8 data);
|
||||
|
||||
required_device<tipi_attached_device> m_rpi;
|
||||
|
||||
int m_address;
|
||||
bool m_dsr;
|
||||
bool m_portaccess;
|
||||
|
||||
// DSR ROM
|
||||
uint8_t* m_eprom;
|
||||
|
||||
// Websocket support
|
||||
std::unique_ptr<webpp::ws_client> m_wsclient;
|
||||
std::shared_ptr<webpp::ws_client::SendStream> m_send_stream;
|
||||
std::unique_ptr<u8[]> m_rpimessage;
|
||||
int m_msgindex;
|
||||
int m_msglength;
|
||||
emu_timer* m_restart_timer;
|
||||
int m_attempts;
|
||||
bool m_connected;
|
||||
|
||||
// Computer interface
|
||||
u8 m_tc;
|
||||
u8 m_td;
|
||||
u8 m_rc;
|
||||
u8 m_rd;
|
||||
};
|
||||
|
||||
/*
|
||||
Defines the connection to the RPi.
|
||||
*/
|
||||
class tipi_attached_device : public device_t, public device_image_interface
|
||||
{
|
||||
public:
|
||||
tipi_attached_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
bool is_readable() const noexcept override { return true; }
|
||||
bool is_writeable() const noexcept override { return true; }
|
||||
bool is_creatable() const noexcept override { return true; }
|
||||
bool is_reset_on_load() const noexcept override { return false; }
|
||||
bool support_command_line_image_creation() const noexcept override { return true; }
|
||||
const char *image_type_name() const noexcept override { return "connect"; }
|
||||
const char *image_brief_type_name() const noexcept override { return "conn"; }
|
||||
const char *image_interface() const noexcept override { return ""; }
|
||||
const char *file_extensions() const noexcept override { return ""; }
|
||||
|
||||
protected:
|
||||
void device_start() override { }
|
||||
void call_unload() override;
|
||||
image_init_result call_load() override;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace bus::ti99::peb
|
||||
|
||||
DECLARE_DEVICE_TYPE_NS(TI99_TIPI_RPI, bus::ti99::peb, tipi_attached_device)
|
||||
DECLARE_DEVICE_TYPE_NS(TI99_TIPI, bus::ti99::peb, tipi_card_device)
|
||||
|
||||
#endif // MAME_BUS_TI99_PEB_TIPI_H
|
Loading…
Reference in New Issue
Block a user