// // Author: Jeremy Rand // Date: July 20, 2012 // // This is the implementation for the Curta emulator UI. // #include #include #include "joystick.h" // Defines #define PREAD 0xFB1E #define ROM_SWITCH 0xC082 #define RAM_SWITCH 0xC080 #define BTN0 0xC061 #define BTN1 0xC062 #define JOYSTICK_CENTER 127 #define JOYSTICK_THRESHOLD 60 #define LOWER_THRESHOLD (JOYSTICK_CENTER - JOYSTICK_THRESHOLD) #define UPPER_THRESHOLD (JOYSTICK_CENTER + JOYSTICK_THRESHOLD) // Globals static tJoyCallbacks *gJoyCallbacks = NULL; static tJoyState gJoyState = { JOY_POS_CENTER, false }; static uint8_t gJoystickTemp; static uint8_t gJoyPollsToNextRead; static uint8_t gJoyPollsToNextRepeat; // Implementation void initJoystick(tJoyCallbacks *callbacks) { gJoyCallbacks = callbacks; gJoyPollsToNextRead = 0; gJoyPollsToNextRepeat = callbacks->initialPollsPerRepeat; } bool isButtonPressed(void) { __asm__ volatile("LDA %w", BTN0); __asm__ volatile("STA %v", gJoystickTemp); if (gJoystickTemp > 127) return true; __asm__ volatile("LDA %w", BTN1); __asm__ volatile("STA %v", gJoystickTemp); return ((gJoystickTemp > 127) ? true : false); } static uint8_t joystickLeftRight(void) { __asm__ volatile("BIT %w", ROM_SWITCH); __asm__ volatile("LDX #0"); __asm__ volatile("SEI"); __asm__ volatile("JSR %w", PREAD); __asm__ volatile("CLI"); __asm__ volatile("STY %v", gJoystickTemp); __asm__ volatile("BIT %w", RAM_SWITCH); return gJoystickTemp; } static uint8_t joystickUpDown(void) { __asm__ volatile("BIT %w", ROM_SWITCH); __asm__ volatile("LDX #1"); __asm__ volatile("SEI"); __asm__ volatile("JSR %w", PREAD); __asm__ volatile("CLI"); __asm__ volatile("STY %v", gJoystickTemp); __asm__ volatile("BIT %w", RAM_SWITCH); return gJoystickTemp; } static void readJoystickState(tJoyState *state) { static bool readLeftRight = true; static uint8_t axisLeftRight = 127; static uint8_t axisUpDown = 127; tJoyPos pos = JOY_POS_CENTER; if (readLeftRight) { int temp = joystickLeftRight(); // Get left/right position temp *= 3; temp /= 4; axisLeftRight /= 4; axisLeftRight += temp; readLeftRight = false; } else { int temp = joystickUpDown(); temp *= 3; temp /= 4; axisUpDown /= 4; axisUpDown += temp; readLeftRight = true; } if (axisLeftRight < LOWER_THRESHOLD) { pos = JOY_POS_LEFT; } else if (axisLeftRight > UPPER_THRESHOLD) { pos = JOY_POS_RIGHT; } state->button = isButtonPressed(); if (axisUpDown < LOWER_THRESHOLD) { switch (pos) { case JOY_POS_LEFT: pos = JOY_POS_UP_LEFT; break; case JOY_POS_RIGHT: pos = JOY_POS_UP_RIGHT; break; default: pos = JOY_POS_UP; break; } } else if (axisUpDown > UPPER_THRESHOLD) { switch (pos) { case JOY_POS_LEFT: pos = JOY_POS_DOWN_LEFT; break; case JOY_POS_RIGHT: pos = JOY_POS_DOWN_RIGHT; break; default: pos = JOY_POS_DOWN; break; } } state->position = pos; } static bool joystickStateChanged(tJoyState *state1, tJoyState *state2) { if ((state1->position != state2->position) || (state1->button != state2->button)) { return true; } return false; } bool pollJoystick(void) { bool result = false; tJoyState newState; if (gJoyPollsToNextRead > 0) { gJoyPollsToNextRead--; return result; } gJoyPollsToNextRead = gJoyCallbacks->pollsPerRead; readJoystickState(&newState); if (joystickStateChanged(&newState, &gJoyState)) { result = (gJoyCallbacks->joyChanged)(&gJoyState, &newState); memcpy(&gJoyState, &newState, sizeof(gJoyState)); gJoyPollsToNextRepeat = gJoyCallbacks->initialPollsPerRepeat; } else { if (gJoyPollsToNextRepeat == 0) { result = (gJoyCallbacks->joyNoChange)(&gJoyState); gJoyPollsToNextRepeat = gJoyCallbacks->pollsPerRepeat; } else { gJoyPollsToNextRepeat--; } } return result; }