1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz, Vas Crabb
3
4 #include "emu.h"
5 #include "pad.h"
6
7 #include <algorithm>
8
9 //#define VERBOSE 1
10 #include "logmacro.h"
11
12
13 //**************************************************************************
14 // GLOBAL VARIABLES
15 //**************************************************************************
16
17 DEFINE_DEVICE_TYPE(VSMILE_PAD, vsmile_pad_device, "vsmile_pad", "V.Smile Joystick")
18
19
20 //**************************************************************************
21 // V.Smile control pad
22 //**************************************************************************
23
vsmile_pad_device(machine_config const & mconfig,char const * tag,device_t * owner,uint32_t clock)24 vsmile_pad_device::vsmile_pad_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
25 : vsmile_pad_device(mconfig, VSMILE_PAD, tag, owner, clock)
26 {
27 }
28
vsmile_pad_device(machine_config const & mconfig,device_type type,char const * tag,device_t * owner,uint32_t clock)29 vsmile_pad_device::vsmile_pad_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, uint32_t clock)
30 : vsmile_ctrl_device_base(mconfig, type, tag, owner, clock)
31 , m_io_joy(*this, "JOY")
32 , m_io_colors(*this, "COLORS")
33 , m_io_buttons(*this, "BUTTONS")
34 , m_sent_joy(0x0000U)
35 , m_sent_colors(0x0000U)
36 , m_sent_buttons(0x0000U)
37 , m_active(false)
38 , m_idle_timer(nullptr)
39 {
40 std::fill(std::begin(m_ctrl_probe_history), std::end(m_ctrl_probe_history), 0U);
41 m_stale = stale_all();
42 }
43
~vsmile_pad_device()44 vsmile_pad_device::~vsmile_pad_device()
45 {
46 }
47
device_start()48 void vsmile_pad_device::device_start()
49 {
50 vsmile_ctrl_device_base::device_start();
51
52 m_idle_timer = machine().scheduler().timer_alloc(
53 timer_expired_delegate(FUNC(vsmile_pad_device::handle_idle), this));
54 m_idle_timer->adjust(attotime::from_seconds(1));
55
56 m_sent_joy = 0x0000U;
57 m_sent_colors = 0x0000U;
58 m_sent_buttons = 0x0000U;
59 m_stale = stale_all();
60 m_active = false;
61
62 save_item(NAME(m_sent_joy));
63 save_item(NAME(m_sent_colors));
64 save_item(NAME(m_sent_buttons));
65 save_item(NAME(m_stale));
66 save_item(NAME(m_active));
67 save_item(NAME(m_ctrl_probe_history));
68 }
69
tx_complete()70 void vsmile_pad_device::tx_complete()
71 {
72 // update joystick
73 if ((m_stale & STALE_JOY) != STALE_NONE)
74 {
75 m_sent_joy = m_io_joy->read();
76 if ((m_stale & STALE_UP_DOWN) != STALE_NONE)
77 {
78 if (BIT(m_sent_joy, 0))
79 uart_tx_fifo_push(0x87); // up
80 else if (BIT(m_sent_joy, 1))
81 uart_tx_fifo_push(0x8f); // down
82 else
83 uart_tx_fifo_push(0x80);
84 }
85 if ((m_stale & STALE_LEFT_RIGHT) != STALE_NONE)
86 {
87 if (BIT(m_sent_joy, 2))
88 uart_tx_fifo_push(0xcf); // left
89 else if (BIT(m_sent_joy, 3))
90 uart_tx_fifo_push(0xc7); // right
91 else
92 uart_tx_fifo_push(0xc0);
93 }
94 }
95
96 // update colors
97 if ((m_stale & STALE_COLORS) != STALE_NONE)
98 {
99 m_sent_colors = m_io_colors->read();
100 uart_tx_fifo_push(0x90 | m_sent_colors);
101 }
102
103 // update buttons
104 if ((m_stale & STALE_BUTTONS) != STALE_NONE)
105 {
106 m_sent_buttons = m_io_buttons->read();
107 if (((m_stale & STALE_OK) != STALE_NONE) && BIT(m_sent_buttons, 0))
108 uart_tx_fifo_push(0xa1);
109 if (((m_stale & STALE_QUIT) != STALE_NONE) && BIT(m_sent_buttons, 1))
110 uart_tx_fifo_push(0xa2);
111 if (((m_stale & STALE_HELP) != STALE_NONE) && BIT(m_sent_buttons, 2))
112 uart_tx_fifo_push(0xa3);
113 if (((m_stale & STALE_ABC) != STALE_NONE) && BIT(m_sent_buttons, 3))
114 uart_tx_fifo_push(0xa4);
115 if (!m_sent_buttons)
116 uart_tx_fifo_push(0xa0);
117 }
118
119 // if nothing happens in the next second we'll queue a keep-alive
120 if (!m_active)
121 LOG("entered active state\n");
122 m_idle_timer->adjust(attotime::from_seconds(1));
123 m_active = true;
124 m_stale = STALE_NONE;
125 }
126
tx_timeout()127 void vsmile_pad_device::tx_timeout()
128 {
129 if (m_active)
130 {
131 m_idle_timer->reset();
132 m_active = false;
133 m_stale = stale_all();
134 std::fill(std::begin(m_ctrl_probe_history), std::end(m_ctrl_probe_history), 0U);
135 LOG("left active state\n");
136 }
137 uart_tx_fifo_push(0x55);
138 }
139
rx_complete(uint8_t data,bool select)140 void vsmile_pad_device::rx_complete(uint8_t data, bool select)
141 {
142 if (select)
143 {
144 if (((data & 0xf0) == 0x70) || ((data & 0xf0) == 0xb0))
145 {
146 m_ctrl_probe_history[0] = ((data & 0xf0) == 0x70) ? 0 : m_ctrl_probe_history[1];
147 m_ctrl_probe_history[1] = data;
148 uint8_t const response = ((m_ctrl_probe_history[0] + m_ctrl_probe_history[1] + 0x0f) & 0x0f) ^ 0x05;
149 LOG(
150 "%s: received probe %02X, %02X, sending response %02X\n",
151 machine().describe_context(),
152 m_ctrl_probe_history[0],
153 m_ctrl_probe_history[1],
154 0xb0 | response);
155 uart_tx_fifo_push(0xb0 | response);
156 }
157 }
158 }
159
uart_tx_fifo_push(uint8_t data)160 void vsmile_pad_device::uart_tx_fifo_push(uint8_t data)
161 {
162 m_idle_timer->reset();
163 queue_tx(data);
164 }
165
TIMER_CALLBACK_MEMBER(vsmile_pad_device::handle_idle)166 TIMER_CALLBACK_MEMBER(vsmile_pad_device::handle_idle)
167 {
168 LOG("idle timer expired, sending keep-alive 55\n");
169 queue_tx(0x55);
170 }
171
INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_joy_changed)172 INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_joy_changed)
173 {
174 if (m_active)
175 {
176 if (!is_tx_empty())
177 {
178 LOG("joy changed while transmission in progress, marking stale\n");
179 m_stale |= stale_pad_inputs(param);
180 }
181 else
182 {
183 uint8_t const joy = m_io_joy->read();
184 if ((joy ^ m_sent_joy) & 0x03)
185 {
186 if (BIT(joy, 0))
187 uart_tx_fifo_push(0x87); // up
188 else if (BIT(joy, 1))
189 uart_tx_fifo_push(0x8f); // down
190 else
191 uart_tx_fifo_push(0x80);
192 }
193 if ((joy ^ m_sent_joy) & 0x0c)
194 {
195 if (BIT(joy, 2))
196 uart_tx_fifo_push(0xcf); // left
197 else if (BIT(joy, 3))
198 uart_tx_fifo_push(0xc7); // right
199 else
200 uart_tx_fifo_push(0xc0);
201 }
202 m_sent_joy = joy;
203 }
204 }
205 }
206
INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_color_changed)207 INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_color_changed)
208 {
209 if (m_active)
210 {
211 if (!is_tx_empty())
212 {
213 LOG("colors changed while transmission in progress, marking stale\n");
214 m_stale |= STALE_COLORS;
215 }
216 else
217 {
218 m_sent_colors = m_io_colors->read();
219 uart_tx_fifo_push(0x90 | m_sent_colors);
220 }
221 }
222 }
223
INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_button_changed)224 INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_button_changed)
225 {
226 if (m_active)
227 {
228 if (!is_tx_empty())
229 {
230 LOG("buttons changed while transmission in progress, marking stale\n");
231 m_stale |= stale_pad_inputs(param);
232 }
233 else
234 {
235 uint8_t const buttons = m_io_buttons->read();
236 if (BIT((m_sent_buttons ^ buttons) & buttons, 0))
237 uart_tx_fifo_push(0xa1);
238 if (BIT((m_sent_buttons ^ buttons) & buttons, 1))
239 uart_tx_fifo_push(0xa2);
240 if (BIT((m_sent_buttons ^ buttons) & buttons, 2))
241 uart_tx_fifo_push(0xa3);
242 if (BIT((m_sent_buttons ^ buttons) & buttons, 3))
243 uart_tx_fifo_push(0xa4);
244 if (!buttons)
245 uart_tx_fifo_push(0xa0);
246 m_sent_buttons = buttons;
247 }
248 }
249 }
250
251 static INPUT_PORTS_START( vsmile_pad )
252 PORT_START("JOY")
PORT_CHANGED_MEMBER(DEVICE_SELF,vsmile_pad_device,pad_joy_changed,vsmile_pad_device::STALE_UP_DOWN)253 PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, vsmile_pad_device::STALE_UP_DOWN) PORT_NAME("Joypad Up")
254 PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, vsmile_pad_device::STALE_UP_DOWN) PORT_NAME("Joypad Down")
255 PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, vsmile_pad_device::STALE_LEFT_RIGHT) PORT_NAME("Joypad Left")
256 PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_joy_changed, vsmile_pad_device::STALE_LEFT_RIGHT) PORT_NAME("Joypad Right")
257 PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED )
258
259 PORT_START("COLORS")
260 PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, vsmile_pad_device::STALE_COLORS) PORT_NAME("Green")
261 PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, vsmile_pad_device::STALE_COLORS) PORT_NAME("Blue")
262 PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, vsmile_pad_device::STALE_COLORS) PORT_NAME("Yellow")
263 PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_color_changed, vsmile_pad_device::STALE_COLORS) PORT_NAME("Red")
264 PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED )
265
266 PORT_START("BUTTONS")
267 PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, vsmile_pad_device::STALE_OK) PORT_NAME("OK")
268 PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, vsmile_pad_device::STALE_QUIT) PORT_NAME("Quit")
269 PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, vsmile_pad_device::STALE_HELP) PORT_NAME("Help")
270 PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_pad_device, pad_button_changed, vsmile_pad_device::STALE_ABC) PORT_NAME("ABC")
271 PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED )
272 INPUT_PORTS_END
273
274 ioport_constructor vsmile_pad_device::device_input_ports() const
275 {
276 return INPUT_PORTS_NAME( vsmile_pad );
277 }
278