Skip to content

Commit 3d6438b

Browse files
committed
Add new pointing device implementation with its unit tests
1 parent b3c56c3 commit 3d6438b

File tree

21 files changed

+693
-30
lines changed

21 files changed

+693
-30
lines changed

src/CDI/CDI.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ class CDI
2727
Callbacks m_callbacks; /**< The user callbacks. */
2828

2929
SCC68070 m_cpu; /**< The main CPU. */
30-
std::unique_ptr<ISlave> m_slave{}; /**< The slave processor. */
3130
std::unique_ptr<IRTC> m_timekeeper{}; /**< The NVRAM chip. */
3231

3332
static std::unique_ptr<CDI> NewCDI(Boards board, bool useSoftCDI, std::span<const uint8_t> systemBios, std::span<const uint8_t> nvram, CDIConfig config = DEFAULT_CDICONFIG, Callbacks callbacks = Callbacks(), CDIDisc disc = CDIDisc());
@@ -51,6 +50,15 @@ class CDI
5150
void Stop(bool wait = true);
5251
bool IsRunning() const { return m_isRunning; }
5352

53+
// TODO: find a way to handle all input device types in a clean way.
54+
virtual void SetUp(bool pressed) noexcept = 0;
55+
virtual void SetRight(bool pressed) noexcept = 0;
56+
virtual void SetDown(bool pressed) noexcept = 0;
57+
virtual void SetLeft(bool pressed) noexcept = 0;
58+
virtual void SetButton1(bool pressed) noexcept = 0;
59+
virtual void SetButton2(bool pressed) noexcept = 0;
60+
virtual void SetButton12(bool pressed) noexcept = 0;
61+
5462
virtual uint8_t PeekByte(uint32_t addr) const noexcept = 0;
5563
virtual uint16_t PeekWord(uint32_t addr) const noexcept = 0;
5664
virtual uint32_t PeekLong(uint32_t addr) const noexcept = 0;
@@ -85,6 +93,7 @@ class CDI
8593
friend SCC68070;
8694

8795
CDIDisc m_disc; /**< CDI disc. */
96+
std::unique_ptr<ISlave> m_slave{}; /**< The slave processor. */
8897

8998
CDI(std::string_view boardName, CDIConfig config, Callbacks callbacks, CDIDisc disc = CDIDisc());
9099

src/CDI/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ add_library(CeDImu ${LIBRARY_TYPE}
3636
CDIFile.cpp
3737
CDIFile.hpp
3838
Export.cpp
39-
PointingDevice.cpp
40-
PointingDevice.hpp
39+
Pointing.cpp
40+
Pointing.hpp
4141
)
4242
target_include_directories(CeDImu PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
4343

src/CDI/HLE/IKAT/IKAT.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ namespace HLE
1515
#define DELAY_RSP(channel, rsp) { delayedRsp[channel] = &rsp; \
1616
delayedRspFrame[channel] = cdi.GetTotalFrameCount() + 2; }
1717

18-
IKAT::IKAT(CDI& idc, bool PAL, uint32_t busbase, PointingDevice::Class deviceClass)
19-
: ISlave(idc, busbase, deviceClass)
18+
IKAT::IKAT(CDI& idc, bool PAL, uint32_t busbase)
19+
: ISlave(idc, busbase)
2020
, registers{0}
2121
, delayedRsp{nullptr}
2222
, delayedRspFrame{0}
@@ -29,16 +29,21 @@ IKAT::IKAT(CDI& idc, bool PAL, uint32_t busbase, PointingDevice::Class deviceCla
2929

3030
void IKAT::UpdatePointerState()
3131
{
32+
std::array<uint8_t, 4> packet{};
33+
const size_t size = pointingDevice.GetState(packet);
34+
3235
channelOut[CHB].clear();
33-
channelOut[CHB].insert(channelOut[CHB].begin(), pointingDevice.m_pointerMessage.begin(), pointingDevice.m_pointerMessage.end());
36+
channelOut[CHB].insert(channelOut[CHB].begin(), packet.begin(), packet.begin() + size);
3437

3538
UNSET_REMTY(CHB_SR)
3639
SET_INT(CHB)
3740
}
3841

3942
void IKAT::IncrementTime(const size_t ns)
4043
{
41-
pointingDevice.IncrementTime(ns);
44+
const bool irq = pointingDevice.IncrementTime(ns);
45+
if(irq) // Got packet.
46+
UpdatePointerState();
4247

4348
for(int channel = CHA; channel <= CHD; channel++)
4449
{

src/CDI/HLE/IKAT/IKAT.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace HLE
1414
class IKAT : public ISlave
1515
{
1616
public:
17-
IKAT(CDI& idc, bool PAL, uint32_t busbase, PointingDevice::Class deviceClass);
17+
IKAT(CDI& idc, bool PAL, uint32_t busbase);
1818

1919
IKAT(const IKAT&) = delete;
2020
IKAT& operator=(const IKAT&) = delete;

src/CDI/Pointing.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/** \file Pointing.cpp
2+
* \brief Implementation of the pointing devices of the CD-I.
3+
*/
4+
5+
#include "Pointing.hpp"
6+
#include "common/utils.hpp"
7+
8+
#include <algorithm>
9+
#include <print>
10+
#include <utility>
11+
12+
namespace Pointing
13+
{
14+
15+
// size_t RelativeCoordinate::GetState(const std::span<uint8_t> packet) noexcept
16+
// {
17+
// std::unique_lock<std::mutex> lock{m_stateMutex};
18+
//
19+
// const uint8_t button1 = static_cast<uint8_t>(m_lastState.btn1) << 5;
20+
// const uint8_t button2 = static_cast<uint8_t>(m_lastState.btn2) << 4;
21+
//
22+
// const uint8_t x = m_lastState.left ? -SPEED : (m_lastState.right ? SPEED : 0);
23+
// const uint8_t y = m_lastState.up ? -SPEED : (m_lastState.down ? SPEED : 0);
24+
//
25+
// std::println("{} {} {} {} {}", SPEED, button1, button2, x, y);
26+
//
27+
// packet[0] = 0x40 | button1 | button2 | (y >> 4 & 0x0C) | (x >> 6 & 3);
28+
// packet[1] = x & 0x3F;
29+
// packet[2] = y & 0x3F;
30+
//
31+
// return BYTES_PER_PACKET;
32+
// }
33+
34+
// bool RelativeCoordinate::IncrementTime(const double ns) noexcept
35+
// {
36+
// // TODO: coroutine?
37+
// bool sendPacket = false;
38+
// std::lock_guard<std::mutex> lock{m_stateMutex};
39+
//
40+
// if(!m_timeNs.has_value()) // Packet can be sent immediately.
41+
// {
42+
// sendPacket = m_state.HasChanged(m_lastState);
43+
// if(sendPacket)
44+
// m_timeNs = 0.0; // Start counting time.
45+
// }
46+
// else // m_timeNs has a value, waiting for packet delay.
47+
// {
48+
// *m_timeNs += ns;
49+
//
50+
// if(*m_timeNs >= PACKET_DELTA)
51+
// {
52+
// sendPacket = m_state.HasChanged(m_lastState);
53+
// if(sendPacket)
54+
// *m_timeNs -= PACKET_DELTA; // Consecutive packet, start counting again.
55+
// else
56+
// m_timeNs = std::nullopt;
57+
// }
58+
// }
59+
//
60+
// if(sendPacket)
61+
// {
62+
// m_lastState = m_state; // To be retrieved later by the Slave chip or driver.
63+
// m_state.ClearDirections();
64+
// }
65+
//
66+
// return sendPacket;
67+
// }
68+
69+
size_t Maneuvering::GetState(const std::span<uint8_t> packet) noexcept
70+
{
71+
const int speed = GetMovementSpeed();
72+
73+
const uint8_t button1 = static_cast<uint8_t>(m_lastState.btn1);
74+
const uint8_t button2 = static_cast<uint8_t>(m_lastState.btn2);
75+
76+
const uint8_t x = m_lastState.left ? -speed : (m_lastState.right ? speed : 0);
77+
const uint8_t y = m_lastState.up ? -speed : (m_lastState.down ? speed : 0);
78+
79+
packet[0] = 0x40 | (button1 << 5) | (button2 << 4) | (y >> 4 & 0x0C) | (x >> 6 & 3);
80+
packet[1] = x & 0x3F;
81+
packet[2] = y & 0x3F;
82+
83+
std::println("{} {} {} {} {}", speed, m_lastState.btn1, m_lastState.btn2, x, y);
84+
85+
return Maneuvering::BYTES_PER_PACKET;
86+
}
87+
88+
bool Maneuvering::IncrementTime(const double ns) noexcept
89+
{
90+
// TODO: coroutine?
91+
bool sendPacket = false;
92+
std::lock_guard<std::mutex> lock{m_stateMutex};
93+
94+
if(!m_timeNs.has_value()) // Packet can be sent immediately.
95+
{
96+
sendPacket = m_state.HasAnyButtonChanged(m_lastState) || m_state.HasPadPressed();
97+
if(sendPacket)
98+
{
99+
m_timeNs = 0.0; // Start counting time.
100+
m_consecutivePackets = 1;
101+
}
102+
}
103+
else // m_timeNs has a value, waiting for packet delay.
104+
{
105+
*m_timeNs += ns;
106+
107+
if(*m_timeNs >= PACKET_DELTA)
108+
{
109+
sendPacket = m_state.HasAnyButtonChanged(m_lastState) || m_state.HasPadPressed();
110+
if(sendPacket) // Consecutive packet, start counting again.
111+
{
112+
*m_timeNs -= PACKET_DELTA;
113+
if(m_state.HasPadPressed())
114+
IncrementConsecutivePacket();
115+
else
116+
m_consecutivePackets = 0;
117+
}
118+
else // No consecutive packet.
119+
{
120+
m_timeNs = std::nullopt;
121+
m_consecutivePackets = 0;
122+
}
123+
}
124+
}
125+
126+
if(sendPacket)
127+
m_lastState = m_state; // To be retrieved later by the Slave chip or driver.
128+
129+
return sendPacket;
130+
}
131+
132+
int Maneuvering::GetMovementSpeed() const noexcept
133+
{
134+
switch(m_speed)
135+
{
136+
case GamepadSpeed::N: return std::min(8, m_consecutivePackets + (m_consecutivePackets & 1));
137+
case GamepadSpeed::I: return 1;
138+
case GamepadSpeed::II: return std::min(16, 2 * m_consecutivePackets);
139+
}
140+
std::unreachable();
141+
}
142+
143+
} // namespace Pointing

0 commit comments

Comments
 (0)