Skip to content

Commit

Permalink
Megaduck Laptop: allow game to run if laptop hardware detection fails…
Browse files Browse the repository at this point in the history
… (is not detected)

- Change laptop hardware init to use timesouts. Init counter sequence seems to require < 1ms timing to capture all returned bytes.
- Gate subsequent laptop keyboard reads with whether laptop was detected
- Improve some function naming
- Enable delete key
  • Loading branch information
bbbbbr committed Nov 30, 2023
1 parent 7c9c92a commit 035113e
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 75 deletions.
2 changes: 2 additions & 0 deletions src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ uint8_t guess_eval[WORD_LENGTH];
bool answer_letter_used[WORD_LENGTH];
bool guess_letter_used[WORD_LENGTH];

bool megaduck_laptop_detected;

uint8_t guess_num;
uint8_t guess_letter_cursor;

Expand Down
2 changes: 2 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#ifndef _COMMON_H
#define _COMMON_H

#include <stdint.h>
#include <stdbool.h>

// Controls whether debug test code is compiled
Expand Down Expand Up @@ -92,6 +93,7 @@ extern char prev_guess[WORD_LENGTH+1];
extern char guess[WORD_LENGTH+1];
extern char word[WORD_LENGTH+1];

extern bool megaduck_laptop_detected;

// Save record signature check
#define STATS_SIG_CHECK_0 0xA50Fu
Expand Down
4 changes: 2 additions & 2 deletions src/gameplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ void gameplay_run(void)
#if defined(MEGADUCK)
// Poll for keyboard keys every other frame
// (Polling intervals below 20ms may cause keyboard lockup)
if (sys_time & 0x01u) {
if ((sys_time & 0x01u) && (megaduck_laptop_detected)) {
if (megaduck_keyboard_poll_keys()) {

megaduck_keyboard_process_keys();
Expand Down Expand Up @@ -322,7 +322,7 @@ void gameplay_run(void)
break;


// case KEY_DELETE: // Fall through, same as backspace
case KEY_DELETE: // Fall through, same as backspace
case KEY_BACKSPACE: // Remove tile and move cursor to left
play_sfx(SFX_TILE_REMOVE);
board_remove_guess_letter();
Expand Down
5 changes: 3 additions & 2 deletions src/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stdbool.h>

#include "input.h"
#include "common.h"

#if (defined(MEGADUCK))
#include "megaduck_laptop/megaduck_keyboard.h"
Expand All @@ -26,7 +27,7 @@ void waitpadreleased_lowcpu(uint8_t button_mask) {

// Poll for keyboard keys every other frame
// (Polling intervals below 20ms may cause keyboard lockup)
if (sys_time & 0x01u) {
if ((sys_time & 0x01u) && (megaduck_laptop_detected)) {
if (megaduck_keyboard_poll_keys()) megaduck_keyboard_process_keys();
}
}
Expand Down Expand Up @@ -66,7 +67,7 @@ void waitpadticked_lowcpu(uint8_t button_mask) {
#if defined(MEGADUCK)
// Poll for keyboard keys every other frame
// (Polling intervals below 20ms may cause keyboard lockup)
if (sys_time & 0x01u) {
if ((sys_time & 0x01u) && (megaduck_laptop_detected)) {

if (megaduck_keyboard_poll_keys()) {
megaduck_keyboard_process_keys();
Expand Down
2 changes: 1 addition & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void main() {
#endif

#if defined(MEGADUCK)
serial_startup();
megaduck_laptop_detected = megaduck_laptop_init();
#endif

fade_out();
Expand Down
126 changes: 62 additions & 64 deletions src/megaduck_laptop/megaduck_laptop_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ volatile uint8_t serial_rx_data;
uint8_t serial_rx_buf[MEGADUCK_RX_MAX_PAYLOAD_LEN];
uint8_t serial_rx_buf_len;

uint8_t serial_system_status;
uint8_t serial_cmd_0x09_reply_data; // In original hardware it's requested, but used for nothing?


Expand Down Expand Up @@ -43,11 +42,10 @@ static void delay_1_msec(void) {

// Waits for a serial transfer to complete with a timeout
//
// - Timeout is about ~ 103 msec or 6.14
// - Timeout length is roughly in msec (100 is about ~ 103 msec or 6.14 frames)
// - Serial ISR populates status var if anything was received
void serial_io_wait_for_transfer_w_timeout_100msec(void) {
uint8_t counter = 0x64u;
while (counter--) {
void serial_io_wait_for_transfer_with_timeout(uint8_t timeout_len_ms) {
while (timeout_len_ms--) {
delay_1_msec();
if (serial_byte_recieved)
return;
Expand Down Expand Up @@ -96,34 +94,26 @@ uint8_t serial_io_read_byte_no_timeout(void) {
}


// Waits for a byte from Serial IO with a timeout (100 msec)
// Waits for a byte from Serial IO with a timeout
// Returns:
// - Timeout length is roughly in msec (100 is about ~ 103 msec or 6.14 frames)
// - If timed out: false
// - If successful: true (rx byte will be in serial_rx_data global)
bool serial_io_wait_receive_timeout_100msec(void) {
bool serial_io_read_byte_with_msecs_timeout(uint8_t timeout_len_ms) {
uint8_t msec_counter;
CRITICAL {
serial_byte_recieved = false;
}

serial_io_enable_receive_byte();
serial_io_wait_for_transfer_w_timeout_100msec();
return serial_byte_recieved;
}


// Waits for a byte from Serial IO with a timeout (200 msec)
// Returns:
// - If timed out: false
// - If successful: true (rx byte will be in serial_rx_data global)
bool serial_io_wait_receive_timeout_200msec(void) {
CRITICAL {
serial_byte_recieved = false;
}
serial_io_enable_receive_byte();

uint8_t timeout = 2u;
while (timeout-- & (!serial_byte_recieved)) {
serial_io_wait_for_transfer_w_timeout_100msec();
while (timeout_len_ms--) {
// Each full run of the inner loop is ~ 1msec
msec_counter = 75u;
while (msec_counter--) {
if (serial_byte_recieved)
return true;
}
}

return serial_byte_recieved;
Expand Down Expand Up @@ -152,7 +142,7 @@ bool serial_io_send_command_and_receive_buffer(uint8_t io_cmd) {
serial_io_send_byte(io_cmd);

// Fail if first rx byte timed out
if (serial_io_wait_receive_timeout_100msec()) {
if (serial_io_read_byte_with_msecs_timeout(TIMEOUT_100_MSEC)) {

// First rx byte will be length of all incoming bytes
if (serial_rx_data <= MEGADUCK_RX_MAX_PAYLOAD_LEN) {
Expand All @@ -164,7 +154,7 @@ bool serial_io_send_command_and_receive_buffer(uint8_t io_cmd) {

while (packet_length--) {
// Wait for next rx byte
if (serial_io_wait_receive_timeout_100msec()) {
if (serial_io_read_byte_with_msecs_timeout(TIMEOUT_100_MSEC)) {
// Save rx byte to buffer and add to checksum
checksum_calc += serial_rx_data;
serial_rx_buf[serial_rx_buf_len++] = serial_rx_data;
Expand Down Expand Up @@ -198,11 +188,11 @@ bool serial_io_send_command_and_receive_buffer(uint8_t io_cmd) {
//
// - Needs to be done any time system is powered on or a cartridge is booted
// - Sends count up sequence + some commands, waits for and checks a count down sequence in reverse
void serial_external_controller_init(void) {
bool megaduck_laptop_controller_init(void) {
uint8_t counter;

IE_REG = SIO_IFLAG;
serial_system_status = SYS_REPLY__BOOT_UNSET;
bool serial_system_init_is_ok = true;

// Send a count up sequence through the serial IO (0,1,2,3...255)
// Exit on 8 bit unsigned wraparound to 0x00
Expand All @@ -211,60 +201,68 @@ void serial_external_controller_init(void) {
serial_io_send_byte(counter++);
} while (counter != 0u);

// Then wait for a response with no timeout
if (serial_io_read_byte_no_timeout() != SYS_REPLY_BOOT_OK) {
serial_system_status |= SYS_REPLY__BOOT_FAIL;
}
// Then wait for a response
// Fail if reply back timed out or was not expected response
if (serial_io_read_byte_with_msecs_timeout(TIMEOUT_2_MSEC)) {
if (serial_rx_data != SYS_REPLY_BOOT_OK) serial_system_init_is_ok = false;
} else
serial_system_init_is_ok = false;

// Send a command that seems to request a 255..0 countdown sequence from the external controller
serial_io_send_byte(SYS_CMD_INIT_SEQ_REQUEST);

// Expects a reply sequence through the serial IO of (255,254,253...0)
counter = 255u;
if (serial_system_init_is_ok) {
serial_io_send_byte(SYS_CMD_INIT_SEQ_REQUEST);

// Expects a reply sequence through the serial IO of (255,254,253...0)
counter = 255u;

// Exit on 8 bit unsigned wraparound to 0xFFu
do {
// Fail if reply back timed out or did not match expected counter
// TODO: OEM approach doesn't break out once a failure occurs,
// but maybe that's possible + sending the abort command early?
if (serial_io_read_byte_with_msecs_timeout(TIMEOUT_2_MSEC)) {
if (counter != serial_rx_data) serial_system_init_is_ok = false;
} else
serial_system_init_is_ok = false;
counter--;
} while (counter != 255u);

// Check for failures during the reply sequence
// and send reply byte based on that
if (serial_system_init_is_ok)
serial_io_send_byte(SYS_CMD_DONE_OR_OK);
else
serial_io_send_byte(SYS_CMD_ABORT_OR_FAIL);
}

// Exit on 8 bit unsigned wraparound to 0xFFu
do {
if (counter != serial_io_read_byte_no_timeout()) {
// This is for serial_system_status_set_fail() { ... }
serial_system_status |= SYS_REPLY__BOOT_FAIL;
}
counter--;
} while (counter != 255u);

// Check for failures during the reply sequence
// and send reply byte based on that
if (serial_system_status & SYS_REPLY__BOOT_FAIL)
serial_io_send_byte(SYS_CMD_ABORT_OR_FAIL);
else
serial_io_send_byte(SYS_CMD_DONE_OR_OK);
return serial_system_init_is_ok;
}



void serial_startup(void) {
bool megaduck_laptop_init(void) {
uint8_t int_enables_saved;
bool laptop_init_is_ok = true;

disable_interrupts();
int_enables_saved = IE_REG;
SC_REG = 0x00u;
SB_REG = 0x00u;

// Initialize Serially attached peripheral
serial_external_controller_init();
while (serial_system_status & SYS_REPLY__BOOT_FAIL);

// Save response from some command
// (so far not seen being used in 32K Bank 0)
serial_io_send_byte(SYS_CMD_INIT_UNKNOWN_0x09);
serial_io_read_byte_no_timeout();
serial_cmd_0x09_reply_data = serial_rx_data;
laptop_init_is_ok = megaduck_laptop_controller_init();
if (laptop_init_is_ok) {
// Save response from some command
// (so far not seen being used in 32K Bank 0)
serial_io_send_byte(SYS_CMD_INIT_UNKNOWN_0x09);
serial_io_read_byte_no_timeout();
serial_cmd_0x09_reply_data = serial_rx_data;
}

// Ignore the RTC init check for now

// general_init__97A_
// vram_init__752_

IE_REG = int_enables_saved;
enable_interrupts();

return (laptop_init_is_ok);
}

13 changes: 8 additions & 5 deletions src/megaduck_laptop/megaduck_laptop_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@

#define MEGADUCK_RX_MAX_PAYLOAD_LEN 14u // 13 data bytes + 1 checksum byte max reply length?

#define TIMEOUT_2_MSEC 2u // Used for hardware init counter sequence
#define TIMEOUT_100_MSEC 100u
#define TIMEOUT_200_MSEC 200u


extern uint8_t serial_cmd_0x09_reply_data;

Expand All @@ -37,15 +41,14 @@ extern volatile uint8_t serial_status;
extern uint8_t serial_rx_buf[MEGADUCK_RX_MAX_PAYLOAD_LEN];
extern uint8_t serial_rx_buf_len;

void serial_io_wait_for_transfer_w_timeout_100msec(void);
void serial_io_wait_for_transfer_with_timeout(uint8_t);
void serial_io_send_byte(uint8_t);
void serial_io_enable_receive_byte(void);
void serial_external_controller_init(void);
void serial_startup(void);
bool megaduck_laptop_controller_init(void);
bool megaduck_laptop_init(void);

bool serial_io_send_command_and_receive_buffer(uint8_t);
bool serial_io_wait_receive_timeout_100msec(void);
bool serial_io_wait_receive_timeout_200msec(void);
bool serial_io_read_byte_with_msecs_timeout(uint8_t);

uint8_t serial_io_read_byte_no_timeout(void);

Expand Down
2 changes: 1 addition & 1 deletion src/settings_menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ void menu_run(void) {
#if defined(MEGADUCK)
// Poll for keyboard keys every other frame
// (Polling intervals below 20ms may cause keyboard lockup)
if (sys_time & 0x01u) {
if ((sys_time & 0x01u) && (megaduck_laptop_detected)) {
if (megaduck_keyboard_poll_keys()) {

megaduck_keyboard_process_keys();
Expand Down

0 comments on commit 035113e

Please sign in to comment.