mirror of
https://github.com/afska/gba-link-connection.git
synced 2026-04-26 02:02:25 -05:00
Adding PS2 libraries
This commit is contained in:
parent
37e01daed0
commit
1ed8195154
284
examples/LinkPS2Keyboard_demo/Makefile
Normal file
284
examples/LinkPS2Keyboard_demo/Makefile
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
#
|
||||
# Template tonc makefile
|
||||
#
|
||||
# Yoinked mostly from DKP's template
|
||||
#
|
||||
|
||||
# === SETUP ===========================================================
|
||||
|
||||
# --- No implicit rules ---
|
||||
.SUFFIXES:
|
||||
|
||||
# --- Paths ---
|
||||
export TONCLIB := ${DEVKITPRO}/libtonc
|
||||
|
||||
# === TONC RULES ======================================================
|
||||
#
|
||||
# Yes, this is almost, but not quite, completely like to
|
||||
# DKP's base_rules and gba_rules
|
||||
#
|
||||
|
||||
export PATH := $(DEVKITARM)/bin:$(PATH)
|
||||
|
||||
|
||||
# --- Executable names ---
|
||||
|
||||
PREFIX ?= arm-none-eabi-
|
||||
|
||||
export CC := $(PREFIX)gcc
|
||||
export CXX := $(PREFIX)g++
|
||||
export AS := $(PREFIX)as
|
||||
export AR := $(PREFIX)ar
|
||||
export NM := $(PREFIX)nm
|
||||
export OBJCOPY := $(PREFIX)objcopy
|
||||
|
||||
# LD defined in Makefile
|
||||
|
||||
|
||||
# === LINK / TRANSLATE ================================================
|
||||
|
||||
%.gba : %.elf
|
||||
@$(OBJCOPY) -O binary $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
@gbafix $@ -t$(TITLE)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.mb.elf :
|
||||
@echo Linking multiboot
|
||||
$(LD) -specs=gba_mb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
$(NM) -Sn $@ > $(basename $(notdir $@)).map
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.elf :
|
||||
@echo Linking cartridge
|
||||
$(LD) -specs=gba.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
$(NM) -Sn $@ > $(basename $(notdir $@)).map
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.a :
|
||||
@echo $(notdir $@)
|
||||
@rm -f $@
|
||||
$(AR) -crs $@ $^
|
||||
|
||||
|
||||
# === OBJECTIFY =======================================================
|
||||
|
||||
%.iwram.o : %.iwram.cpp
|
||||
@echo $(notdir $<)
|
||||
$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(IARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
%.iwram.o : %.iwram.c
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(IARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.cpp
|
||||
@echo $(notdir $<)
|
||||
$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(RARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.c
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(RARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.s
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.S
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# canned command sequence for binary data
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(<F) | tr . _)`.h
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(<F) | tr . _)`.h
|
||||
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(<F) | tr . _)`.h
|
||||
endef
|
||||
# =====================================================================
|
||||
|
||||
# --- Main path ---
|
||||
|
||||
export PATH := $(DEVKITARM)/bin:$(PATH)
|
||||
|
||||
|
||||
# === PROJECT DETAILS =================================================
|
||||
# PROJ : Base project name
|
||||
# TITLE : Title for ROM header (12 characters)
|
||||
# LIBS : Libraries to use, formatted as list for linker flags
|
||||
# BUILD : Directory for build process temporaries. Should NOT be empty!
|
||||
# SRCDIRS : List of source file directories
|
||||
# DATADIRS : List of data file directories
|
||||
# INCDIRS : List of header file directories
|
||||
# LIBDIRS : List of library directories
|
||||
# General note: use `.' for the current dir, don't leave the lists empty.
|
||||
|
||||
export PROJ ?= $(notdir $(CURDIR))
|
||||
TITLE := $(PROJ)
|
||||
|
||||
LIBS := -ltonc -lugba
|
||||
|
||||
BUILD := build
|
||||
SRCDIRS := src ../_lib ../../lib
|
||||
DATADIRS := data
|
||||
INCDIRS := src
|
||||
LIBDIRS := $(TONCLIB) $(PWD)/../_lib/libugba
|
||||
|
||||
# --- switches ---
|
||||
|
||||
bMB := 0 # Multiboot build
|
||||
bTEMPS := 0 # Save gcc temporaries (.i and .s files)
|
||||
bDEBUG2 := 0 # Generate debug info (bDEBUG2? Not a full DEBUG flag. Yet)
|
||||
|
||||
|
||||
# === BUILD FLAGS =====================================================
|
||||
# This is probably where you can stop editing
|
||||
# NOTE: I've noticed that -fgcse and -ftree-loop-optimize sometimes muck
|
||||
# up things (gcse seems fond of building masks inside a loop instead of
|
||||
# outside them for example). Removing them sometimes helps
|
||||
|
||||
# --- Architecture ---
|
||||
|
||||
ARCH := -mthumb-interwork -mthumb
|
||||
RARCH := -mthumb-interwork -mthumb
|
||||
IARCH := -mthumb-interwork -marm -mlong-calls
|
||||
|
||||
# --- Main flags ---
|
||||
|
||||
CFLAGS := -mcpu=arm7tdmi -mtune=arm7tdmi -O2
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += $(INCLUDE)
|
||||
CFLAGS += -ffast-math -fno-strict-aliasing
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := $(ARCH) $(INCLUDE)
|
||||
LDFLAGS := $(ARCH) -Wl,-Map,$(PROJ).map
|
||||
|
||||
# --- switched additions ----------------------------------------------
|
||||
|
||||
# --- Multiboot ? ---
|
||||
ifeq ($(strip $(bMB)), 1)
|
||||
TARGET := $(PROJ).mb
|
||||
else
|
||||
TARGET := $(PROJ)
|
||||
endif
|
||||
|
||||
# --- Save temporary files ? ---
|
||||
ifeq ($(strip $(bTEMPS)), 1)
|
||||
CFLAGS += -save-temps
|
||||
CXXFLAGS += -save-temps
|
||||
endif
|
||||
|
||||
# --- Debug info ? ---
|
||||
|
||||
ifeq ($(strip $(bDEBUG)), 1)
|
||||
CFLAGS += -DDEBUG -g
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
ASFLAGS += -DDEBUG -g
|
||||
LDFLAGS += -g
|
||||
else
|
||||
CFLAGS += -DNDEBUG
|
||||
CXXFLAGS += -DNDEBUG
|
||||
ASFLAGS += -DNDEBUG
|
||||
endif
|
||||
|
||||
|
||||
# === BUILD PROC ======================================================
|
||||
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
|
||||
# Still in main dir:
|
||||
# * Define/export some extra variables
|
||||
# * Invoke this file again from the build dir
|
||||
# PONDER: what happens if BUILD == "" ?
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export VPATH := \
|
||||
$(foreach dir, $(SRCDIRS) , $(CURDIR)/$(dir)) \
|
||||
$(foreach dir, $(DATADIRS), $(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
# --- List source and data files ---
|
||||
|
||||
CFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir, $(DATADIRS), $(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
# --- Set linker depending on C++ file existence ---
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
export LD := $(CC)
|
||||
else
|
||||
export LD := $(CXX)
|
||||
endif
|
||||
|
||||
# --- Define object file list ---
|
||||
export OFILES := $(addsuffix .o, $(BINFILES)) \
|
||||
$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) \
|
||||
$(SFILES:.s=.o)
|
||||
|
||||
# --- Create include and library search paths ---
|
||||
export INCLUDE := $(foreach dir,$(INCDIRS),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := -L$(CURDIR) $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
# --- Create BUILD if necessary, and run this makefile from there ---
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
arm-none-eabi-nm -Sn $(OUTPUT).elf > $(BUILD)/$(TARGET).map
|
||||
|
||||
all : $(BUILD)
|
||||
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -rf $(BUILD) $(TARGET).elf $(TARGET).gba $(TARGET).sav
|
||||
|
||||
|
||||
else # If we're here, we should be in the BUILD dir
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
# --- Main targets ----
|
||||
|
||||
$(OUTPUT).gba : $(OUTPUT).elf
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
|
||||
endif # End BUILD switch
|
||||
|
||||
# --- More targets ----------------------------------------------------
|
||||
|
||||
.PHONY: clean rebuild start
|
||||
|
||||
rebuild: clean $(BUILD)
|
||||
|
||||
start:
|
||||
start "$(TARGET).gba"
|
||||
|
||||
restart: rebuild start
|
||||
|
||||
# EOF
|
||||
67
examples/LinkPS2Keyboard_demo/src/main.cpp
Normal file
67
examples/LinkPS2Keyboard_demo/src/main.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#include <tonc.h>
|
||||
#include <string>
|
||||
#include "../../_lib/interrupt.h"
|
||||
|
||||
// (0) Include the header
|
||||
#include "../../../lib/LinkPS2Keyboard.hpp"
|
||||
|
||||
void log(std::string text);
|
||||
static std::string output = "";
|
||||
static u32 irqs = 0;
|
||||
inline void VBLANK() {}
|
||||
void SERIAL() {
|
||||
LINK_PS2_KEYBOARD_ISR_SERIAL();
|
||||
irqs++;
|
||||
}
|
||||
|
||||
// (1) Create a LinkPS2Keyboard instance
|
||||
LinkPS2Keyboard* linkPS2Keyboard = new LinkPS2Keyboard([](u8 event) {
|
||||
// (4) Handle events in the callback sent to LinkPS2Keyboard's constructor!
|
||||
output += std::to_string(event) + "|";
|
||||
});
|
||||
|
||||
void init() {
|
||||
REG_DISPCNT = DCNT_MODE0 | DCNT_BG0;
|
||||
tte_init_se_default(0, BG_CBB(0) | BG_SBB(31));
|
||||
|
||||
// (2) Add the interrupt service routines
|
||||
interrupt_init();
|
||||
interrupt_set_handler(INTR_VBLANK, VBLANK);
|
||||
interrupt_enable(INTR_VBLANK);
|
||||
interrupt_set_handler(INTR_SERIAL, SERIAL);
|
||||
interrupt_enable(INTR_SERIAL);
|
||||
}
|
||||
|
||||
int main() {
|
||||
init();
|
||||
|
||||
while (true) {
|
||||
std::string output = "LinkPS2Keyboard_demo (v6.3.0)\n\n";
|
||||
u16 keys = ~REG_KEYS & KEY_ANY;
|
||||
|
||||
if (!linkPS2Keyboard->isActive()) {
|
||||
output += "Press A to read keyboard input";
|
||||
|
||||
if (keys & KEY_A) {
|
||||
// (3) Initialize the library
|
||||
log("Waiting...");
|
||||
linkPS2Keyboard->activate();
|
||||
VBlankIntrWait();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Print
|
||||
VBlankIntrWait();
|
||||
LINK_PS2_KEYBOARD_ISR_VBLANK();
|
||||
log(output);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void log(std::string text) {
|
||||
tte_erase_screen();
|
||||
tte_write("#{P:0,0}");
|
||||
tte_write(text.c_str());
|
||||
}
|
||||
284
examples/LinkPS2Mouse_demo/Makefile
Normal file
284
examples/LinkPS2Mouse_demo/Makefile
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
#
|
||||
# Template tonc makefile
|
||||
#
|
||||
# Yoinked mostly from DKP's template
|
||||
#
|
||||
|
||||
# === SETUP ===========================================================
|
||||
|
||||
# --- No implicit rules ---
|
||||
.SUFFIXES:
|
||||
|
||||
# --- Paths ---
|
||||
export TONCLIB := ${DEVKITPRO}/libtonc
|
||||
|
||||
# === TONC RULES ======================================================
|
||||
#
|
||||
# Yes, this is almost, but not quite, completely like to
|
||||
# DKP's base_rules and gba_rules
|
||||
#
|
||||
|
||||
export PATH := $(DEVKITARM)/bin:$(PATH)
|
||||
|
||||
|
||||
# --- Executable names ---
|
||||
|
||||
PREFIX ?= arm-none-eabi-
|
||||
|
||||
export CC := $(PREFIX)gcc
|
||||
export CXX := $(PREFIX)g++
|
||||
export AS := $(PREFIX)as
|
||||
export AR := $(PREFIX)ar
|
||||
export NM := $(PREFIX)nm
|
||||
export OBJCOPY := $(PREFIX)objcopy
|
||||
|
||||
# LD defined in Makefile
|
||||
|
||||
|
||||
# === LINK / TRANSLATE ================================================
|
||||
|
||||
%.gba : %.elf
|
||||
@$(OBJCOPY) -O binary $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
@gbafix $@ -t$(TITLE)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.mb.elf :
|
||||
@echo Linking multiboot
|
||||
$(LD) -specs=gba_mb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
$(NM) -Sn $@ > $(basename $(notdir $@)).map
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.elf :
|
||||
@echo Linking cartridge
|
||||
$(LD) -specs=gba.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
$(NM) -Sn $@ > $(basename $(notdir $@)).map
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.a :
|
||||
@echo $(notdir $@)
|
||||
@rm -f $@
|
||||
$(AR) -crs $@ $^
|
||||
|
||||
|
||||
# === OBJECTIFY =======================================================
|
||||
|
||||
%.iwram.o : %.iwram.cpp
|
||||
@echo $(notdir $<)
|
||||
$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(IARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
%.iwram.o : %.iwram.c
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(IARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.cpp
|
||||
@echo $(notdir $<)
|
||||
$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(RARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.c
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(RARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.s
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.S
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# canned command sequence for binary data
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(<F) | tr . _)`.h
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(<F) | tr . _)`.h
|
||||
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(<F) | tr . _)`.h
|
||||
endef
|
||||
# =====================================================================
|
||||
|
||||
# --- Main path ---
|
||||
|
||||
export PATH := $(DEVKITARM)/bin:$(PATH)
|
||||
|
||||
|
||||
# === PROJECT DETAILS =================================================
|
||||
# PROJ : Base project name
|
||||
# TITLE : Title for ROM header (12 characters)
|
||||
# LIBS : Libraries to use, formatted as list for linker flags
|
||||
# BUILD : Directory for build process temporaries. Should NOT be empty!
|
||||
# SRCDIRS : List of source file directories
|
||||
# DATADIRS : List of data file directories
|
||||
# INCDIRS : List of header file directories
|
||||
# LIBDIRS : List of library directories
|
||||
# General note: use `.' for the current dir, don't leave the lists empty.
|
||||
|
||||
export PROJ ?= $(notdir $(CURDIR))
|
||||
TITLE := $(PROJ)
|
||||
|
||||
LIBS := -ltonc -lugba
|
||||
|
||||
BUILD := build
|
||||
SRCDIRS := src ../_lib ../../lib
|
||||
DATADIRS := data
|
||||
INCDIRS := src
|
||||
LIBDIRS := $(TONCLIB) $(PWD)/../_lib/libugba
|
||||
|
||||
# --- switches ---
|
||||
|
||||
bMB := 0 # Multiboot build
|
||||
bTEMPS := 0 # Save gcc temporaries (.i and .s files)
|
||||
bDEBUG2 := 0 # Generate debug info (bDEBUG2? Not a full DEBUG flag. Yet)
|
||||
|
||||
|
||||
# === BUILD FLAGS =====================================================
|
||||
# This is probably where you can stop editing
|
||||
# NOTE: I've noticed that -fgcse and -ftree-loop-optimize sometimes muck
|
||||
# up things (gcse seems fond of building masks inside a loop instead of
|
||||
# outside them for example). Removing them sometimes helps
|
||||
|
||||
# --- Architecture ---
|
||||
|
||||
ARCH := -mthumb-interwork -mthumb
|
||||
RARCH := -mthumb-interwork -mthumb
|
||||
IARCH := -mthumb-interwork -marm -mlong-calls
|
||||
|
||||
# --- Main flags ---
|
||||
|
||||
CFLAGS := -mcpu=arm7tdmi -mtune=arm7tdmi -O2
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += $(INCLUDE)
|
||||
CFLAGS += -ffast-math -fno-strict-aliasing
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := $(ARCH) $(INCLUDE)
|
||||
LDFLAGS := $(ARCH) -Wl,-Map,$(PROJ).map
|
||||
|
||||
# --- switched additions ----------------------------------------------
|
||||
|
||||
# --- Multiboot ? ---
|
||||
ifeq ($(strip $(bMB)), 1)
|
||||
TARGET := $(PROJ).mb
|
||||
else
|
||||
TARGET := $(PROJ)
|
||||
endif
|
||||
|
||||
# --- Save temporary files ? ---
|
||||
ifeq ($(strip $(bTEMPS)), 1)
|
||||
CFLAGS += -save-temps
|
||||
CXXFLAGS += -save-temps
|
||||
endif
|
||||
|
||||
# --- Debug info ? ---
|
||||
|
||||
ifeq ($(strip $(bDEBUG)), 1)
|
||||
CFLAGS += -DDEBUG -g
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
ASFLAGS += -DDEBUG -g
|
||||
LDFLAGS += -g
|
||||
else
|
||||
CFLAGS += -DNDEBUG
|
||||
CXXFLAGS += -DNDEBUG
|
||||
ASFLAGS += -DNDEBUG
|
||||
endif
|
||||
|
||||
|
||||
# === BUILD PROC ======================================================
|
||||
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
|
||||
# Still in main dir:
|
||||
# * Define/export some extra variables
|
||||
# * Invoke this file again from the build dir
|
||||
# PONDER: what happens if BUILD == "" ?
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export VPATH := \
|
||||
$(foreach dir, $(SRCDIRS) , $(CURDIR)/$(dir)) \
|
||||
$(foreach dir, $(DATADIRS), $(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
# --- List source and data files ---
|
||||
|
||||
CFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir, $(DATADIRS), $(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
# --- Set linker depending on C++ file existence ---
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
export LD := $(CC)
|
||||
else
|
||||
export LD := $(CXX)
|
||||
endif
|
||||
|
||||
# --- Define object file list ---
|
||||
export OFILES := $(addsuffix .o, $(BINFILES)) \
|
||||
$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) \
|
||||
$(SFILES:.s=.o)
|
||||
|
||||
# --- Create include and library search paths ---
|
||||
export INCLUDE := $(foreach dir,$(INCDIRS),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := -L$(CURDIR) $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
# --- Create BUILD if necessary, and run this makefile from there ---
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
arm-none-eabi-nm -Sn $(OUTPUT).elf > $(BUILD)/$(TARGET).map
|
||||
|
||||
all : $(BUILD)
|
||||
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -rf $(BUILD) $(TARGET).elf $(TARGET).gba $(TARGET).sav
|
||||
|
||||
|
||||
else # If we're here, we should be in the BUILD dir
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
# --- Main targets ----
|
||||
|
||||
$(OUTPUT).gba : $(OUTPUT).elf
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
|
||||
endif # End BUILD switch
|
||||
|
||||
# --- More targets ----------------------------------------------------
|
||||
|
||||
.PHONY: clean rebuild start
|
||||
|
||||
rebuild: clean $(BUILD)
|
||||
|
||||
start:
|
||||
start "$(TARGET).gba"
|
||||
|
||||
restart: rebuild start
|
||||
|
||||
# EOF
|
||||
64
examples/LinkPS2Mouse_demo/src/main.cpp
Normal file
64
examples/LinkPS2Mouse_demo/src/main.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#include <tonc.h>
|
||||
#include <string>
|
||||
#include "../../_lib/interrupt.h"
|
||||
|
||||
// (0) Include the header
|
||||
#include "../../../lib/LinkPS2Mouse.hpp"
|
||||
|
||||
void log(std::string text);
|
||||
inline void VBLANK() {}
|
||||
inline void TIMER() {}
|
||||
|
||||
// (1) Create a LinkPS2Mouse instance
|
||||
LinkPS2Mouse* linkPS2Mouse = new LinkPS2Mouse(2);
|
||||
|
||||
void init() {
|
||||
REG_DISPCNT = DCNT_MODE0 | DCNT_BG0;
|
||||
tte_init_se_default(0, BG_CBB(0) | BG_SBB(31));
|
||||
|
||||
// (2) Add the interrupt service routines
|
||||
interrupt_init();
|
||||
interrupt_set_handler(INTR_VBLANK, VBLANK);
|
||||
interrupt_enable(INTR_VBLANK);
|
||||
interrupt_set_handler(INTR_TIMER2, VBLANK);
|
||||
interrupt_enable(INTR_TIMER2);
|
||||
}
|
||||
|
||||
int main() {
|
||||
init();
|
||||
|
||||
while (true) {
|
||||
std::string output = "LinkPS2Mouse_demo (v6.3.0)\n\n";
|
||||
u16 keys = ~REG_KEYS & KEY_ANY;
|
||||
|
||||
if (!linkPS2Mouse->isActive()) {
|
||||
output += "Press A to read mouse input";
|
||||
|
||||
if (keys & KEY_A) {
|
||||
// (3) Initialize the library
|
||||
log("Waiting...");
|
||||
linkPS2Mouse->activate();
|
||||
VBlankIntrWait();
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// (4) Get a report
|
||||
int data[3];
|
||||
linkPS2Mouse->report(data);
|
||||
log(std::to_string(data[0]) + ": " + "(" + std::to_string(data[1]) +
|
||||
", " + std::to_string(data[2]) + ")");
|
||||
}
|
||||
|
||||
// Print
|
||||
VBlankIntrWait();
|
||||
log(output);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void log(std::string text) {
|
||||
tte_erase_screen();
|
||||
tte_write("#{P:0,0}");
|
||||
tte_write(text.c_str());
|
||||
}
|
||||
120
lib/LinkPS2Keyboard.hpp
Normal file
120
lib/LinkPS2Keyboard.hpp
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
#ifndef LINK_PS2_KEYBOARD_H
|
||||
#define LINK_PS2_KEYBOARD_H
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// A PS/2 Keyboard Adapter for the GBA
|
||||
// --------------------------------------------------------------------------
|
||||
// Usage:
|
||||
// - 1) Include this header in your main.cpp file and add:
|
||||
// LinkPS2Keyboard* linkPS2Keyboard = new LinkPS2Keyboard([](u8 event) {
|
||||
// // handle event
|
||||
// });
|
||||
// - 2) Add the required interrupt service routines: (*)
|
||||
// irq_init(NULL);
|
||||
// irq_add(II_VBLANK, LINK_PS2_KEYBOARD_ISR_VBLANK);
|
||||
// irq_add(II_SERIAL, LINK_PS2_KEYBOARD_ISR_SERIAL);
|
||||
// - 3) Initialize the library with:
|
||||
// linkPS2Keyboard->activate();
|
||||
// - 4) Handle events in the callback sent to LinkPS2Keyboard's constructor!
|
||||
// --------------------------------------------------------------------------
|
||||
// ____________
|
||||
// | Pinout |
|
||||
// |PS/2 --- GBA|
|
||||
// |------------|
|
||||
// |CLOCK -> SI |
|
||||
// |DATA --> SO |
|
||||
// |VCC ---> VCC|
|
||||
// |GND ---> GND|
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#include <tonc_core.h>
|
||||
#include <functional>
|
||||
|
||||
#define LINK_PS2_KEYBOARD_SI_DIRECTION 0b1000000
|
||||
#define LINK_PS2_KEYBOARD_SO_DIRECTION 0b10000000
|
||||
#define LINK_PS2_KEYBOARD_SI_DATA 0b100
|
||||
#define LINK_PS2_KEYBOARD_SO_DATA 0b1000
|
||||
#define LINK_PS2_KEYBOARD_TIMEOUT_FRAMES 15 // (~250ms)
|
||||
|
||||
static volatile char LINK_PS2_KEYBOARD_VERSION[] = "LinkPS2Keyboard/v6.3.0";
|
||||
|
||||
class LinkPS2Keyboard {
|
||||
public:
|
||||
explicit LinkPS2Keyboard(std::function<void(u8 event)> onEvent) {
|
||||
this->onEvent = onEvent;
|
||||
}
|
||||
|
||||
bool isActive() { return isEnabled; }
|
||||
|
||||
void activate() {
|
||||
deactivate();
|
||||
|
||||
REG_RCNT = 0b1000000100000000; // General Purpose Mode + SI interrupts
|
||||
REG_SIOCNT = 0; // Unused
|
||||
|
||||
bitcount = 0;
|
||||
incoming = 0;
|
||||
prevFrame = 0;
|
||||
frameCounter = 0;
|
||||
|
||||
isEnabled = true;
|
||||
}
|
||||
|
||||
void deactivate() {
|
||||
isEnabled = false;
|
||||
|
||||
REG_RCNT = 0b1000000000000000; // General Purpose Mode
|
||||
REG_SIOCNT = 0; // Unused
|
||||
}
|
||||
|
||||
void _onVBlank() { frameCounter++; }
|
||||
|
||||
void _onSerial() {
|
||||
u8 val = (REG_RCNT & LINK_PS2_KEYBOARD_SO_DATA) != 0;
|
||||
|
||||
u32 nowFrame = frameCounter;
|
||||
if (nowFrame - prevFrame > LINK_PS2_KEYBOARD_TIMEOUT_FRAMES) {
|
||||
bitcount = 0;
|
||||
incoming = 0;
|
||||
}
|
||||
prevFrame = nowFrame;
|
||||
|
||||
u8 n = bitcount - 1;
|
||||
if (n <= 7)
|
||||
incoming |= (val << n);
|
||||
bitcount++;
|
||||
|
||||
if (bitcount == 11) {
|
||||
onEvent(incoming);
|
||||
|
||||
bitcount = 0;
|
||||
incoming = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool isEnabled = false;
|
||||
uint8_t bitcount = 0;
|
||||
uint8_t incoming = 0;
|
||||
uint32_t prevFrame = 0;
|
||||
u32 frameCounter = 0;
|
||||
std::function<void(u8 event)> onEvent;
|
||||
};
|
||||
|
||||
extern LinkPS2Keyboard* linkPS2Keyboard;
|
||||
|
||||
inline void LINK_PS2_KEYBOARD_ISR_VBLANK() {
|
||||
if (!linkPS2Keyboard->isActive())
|
||||
return;
|
||||
|
||||
linkPS2Keyboard->_onVBlank();
|
||||
}
|
||||
|
||||
inline void LINK_PS2_KEYBOARD_ISR_SERIAL() {
|
||||
if (!linkPS2Keyboard->isActive())
|
||||
return;
|
||||
|
||||
linkPS2Keyboard->_onSerial();
|
||||
}
|
||||
|
||||
#endif // LINK_PS2_KEYBOARD_H
|
||||
238
lib/LinkPS2Mouse.hpp
Normal file
238
lib/LinkPS2Mouse.hpp
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
#ifndef LINK_PS2_MOUSE_H
|
||||
#define LINK_PS2_MOUSE_H
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// A PS/2 Mouse Adapter for the GBA
|
||||
// (Based on https://github.com/kristopher/PS2-Mouse-Arduino, MIT license)
|
||||
// --------------------------------------------------------------------------
|
||||
// Usage:
|
||||
// - 1) Include this header in your main.cpp file and add:
|
||||
// LinkPS2Mouse* linkPS2Mouse = new LinkPS2Mouse();
|
||||
// - 2) Add the required interrupt service routines: (*)
|
||||
// irq_init(NULL);
|
||||
// irq_add(II_TIMER2, NULL);
|
||||
// - 3) Initialize the library with:
|
||||
// linkPS2Mouse->activate();
|
||||
// - 4) Get a report:
|
||||
// int data[3];
|
||||
// linkPS2Mouse->report(data);
|
||||
// if ((data[0] & LINK_PS2_MOUSE_LEFT_CLICK) != 0)
|
||||
// ; // handle LEFT click
|
||||
// data[1] // X movement
|
||||
// data[2] // Y movement
|
||||
// --------------------------------------------------------------------------
|
||||
// ____________
|
||||
// | Pinout |
|
||||
// |PS/2 --- GBA|
|
||||
// |------------|
|
||||
// |CLOCK -> SI |
|
||||
// |DATA --> SO |
|
||||
// |VCC ---> VCC|
|
||||
// |GND ---> GND|
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#include <tonc_bios.h>
|
||||
#include <tonc_core.h>
|
||||
|
||||
#define LINK_PS2_MOUSE_LEFT_CLICK 0b001
|
||||
#define LINK_PS2_MOUSE_RIGHT_CLICK 0b010
|
||||
#define LINK_PS2_MOUSE_MIDDLE_CLICK 0b100
|
||||
|
||||
#define LINK_PS2_MOUSE_SI_DIRECTION 0b1000000
|
||||
#define LINK_PS2_MOUSE_SO_DIRECTION 0b10000000
|
||||
#define LINK_PS2_MOUSE_SI_DATA 0b100
|
||||
#define LINK_PS2_MOUSE_SO_DATA 0b1000
|
||||
#define LINK_PS2_MOUSE_TO_TICKS 17
|
||||
|
||||
const u16 LINK_PS2_MOUSE_IRQ_IDS[] = {IRQ_TIMER0, IRQ_TIMER1, IRQ_TIMER2,
|
||||
IRQ_TIMER3};
|
||||
|
||||
static volatile char LINK_PS2_MOUSE_VERSION[] = "LinkPS2Mouse/v6.3.0";
|
||||
|
||||
class LinkPS2Mouse {
|
||||
public:
|
||||
explicit LinkPS2Mouse(u8 waitTimerId) { this->waitTimerId = waitTimerId; }
|
||||
|
||||
bool isActive() { return isEnabled; }
|
||||
|
||||
void activate() {
|
||||
deactivate();
|
||||
|
||||
setClockHigh();
|
||||
setDataHigh();
|
||||
waitMilliseconds(20);
|
||||
write(0xff); // send reset to the mouse
|
||||
readByte(); // read ack byte
|
||||
waitMilliseconds(20); // not sure why this needs the delay
|
||||
readByte(); // blank
|
||||
readByte(); // blank
|
||||
waitMilliseconds(20); // not sure why this needs the delay
|
||||
enableDataReporting(); // tell the mouse to start sending data
|
||||
waitMicroseconds(100);
|
||||
|
||||
isEnabled = true;
|
||||
}
|
||||
|
||||
void deactivate() {
|
||||
isEnabled = false;
|
||||
|
||||
REG_RCNT = 0b1000000000000000; // General Purpose Mode
|
||||
REG_SIOCNT = 0; // Unused
|
||||
}
|
||||
|
||||
void report(int (&data)[3]) {
|
||||
write(0xeb); // send read data
|
||||
readByte(); // read ack byte
|
||||
data[0] = readByte(); // status bit
|
||||
data[1] = readMovementX(data[0]); // X movement packet
|
||||
data[2] = readMovementY(data[0]); // Y movement packet
|
||||
}
|
||||
|
||||
private:
|
||||
u8 waitTimerId;
|
||||
volatile bool isEnabled = false;
|
||||
|
||||
void enableDataReporting() {
|
||||
write(0xf4); // send enable data reporting
|
||||
readByte(); // read ack byte
|
||||
}
|
||||
|
||||
s16 readMovementX(int status) {
|
||||
s16 x = readByte();
|
||||
if ((status & (1 << 4)) != 0)
|
||||
// negative
|
||||
for (int i = 8; i < 16; i++)
|
||||
x |= 1 << i;
|
||||
return x;
|
||||
}
|
||||
|
||||
s16 readMovementY(int status) {
|
||||
s16 y = readByte();
|
||||
if ((status & (1 << 5)) != 0)
|
||||
// negative
|
||||
for (int i = 8; i < 16; i++)
|
||||
y |= 1 << i;
|
||||
return y;
|
||||
}
|
||||
|
||||
void write(u8 data) {
|
||||
u8 parity = 1;
|
||||
setDataHigh();
|
||||
setClockHigh();
|
||||
waitMicroseconds(300);
|
||||
setClockLow();
|
||||
waitMicroseconds(300);
|
||||
setDataLow();
|
||||
waitMicroseconds(10);
|
||||
setClockHigh(); // (start bit)
|
||||
while (getClock())
|
||||
; // wait for mouse to take control of clock
|
||||
// clock is low, and we are clear to send data
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
if (data & 0x01)
|
||||
setDataHigh();
|
||||
else
|
||||
setDataLow();
|
||||
// wait for clock cycle
|
||||
while (!getClock())
|
||||
;
|
||||
while (getClock())
|
||||
;
|
||||
parity = parity ^ (data & 0x01);
|
||||
data = data >> 1;
|
||||
}
|
||||
// parity
|
||||
if (parity)
|
||||
setDataHigh();
|
||||
else
|
||||
setDataLow();
|
||||
while (!getClock())
|
||||
;
|
||||
while (getClock())
|
||||
;
|
||||
setDataHigh();
|
||||
waitMicroseconds(50);
|
||||
while (getClock())
|
||||
;
|
||||
while (!getClock() || !getData())
|
||||
; // wait for mouse to switch modes
|
||||
setClockLow(); // put a hold on the incoming data.
|
||||
}
|
||||
|
||||
u8 readByte() {
|
||||
u8 data = 0;
|
||||
setClockHigh();
|
||||
setDataHigh();
|
||||
waitMicroseconds(50);
|
||||
while (getClock())
|
||||
;
|
||||
while (!getClock())
|
||||
; // eat start bit
|
||||
for (int i = 0; i < 8; i++) {
|
||||
data |= readBit() << i;
|
||||
}
|
||||
readBit(); // parity bit
|
||||
readBit(); // stop bit should be 1
|
||||
setClockLow();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool readBit() {
|
||||
while (getClock())
|
||||
;
|
||||
bool bit = getData();
|
||||
while (!getClock())
|
||||
;
|
||||
return bit;
|
||||
}
|
||||
|
||||
void waitMilliseconds(u16 milliseconds) {
|
||||
u16 ticksOf1024Cycles = milliseconds * LINK_PS2_MOUSE_TO_TICKS;
|
||||
REG_TM[waitTimerId].start = -ticksOf1024Cycles;
|
||||
REG_TM[waitTimerId].cnt = TM_ENABLE | TM_IRQ | TM_FREQ_1024;
|
||||
IntrWait(1, LINK_PS2_MOUSE_IRQ_IDS[waitTimerId]);
|
||||
REG_TM[waitTimerId].cnt = 0;
|
||||
}
|
||||
|
||||
void waitMicroseconds(u16 microseconds) {
|
||||
u16 cycles = microseconds * LINK_PS2_MOUSE_TO_TICKS;
|
||||
REG_TM[waitTimerId].start = -cycles;
|
||||
REG_TM[waitTimerId].cnt = TM_ENABLE | TM_IRQ | TM_FREQ_1;
|
||||
IntrWait(1, LINK_PS2_MOUSE_IRQ_IDS[waitTimerId]);
|
||||
REG_TM[waitTimerId].cnt = 0;
|
||||
}
|
||||
|
||||
bool getClock() {
|
||||
REG_RCNT &= ~LINK_PS2_MOUSE_SI_DIRECTION;
|
||||
return (REG_RCNT & LINK_PS2_MOUSE_SI_DATA) >> 0;
|
||||
}
|
||||
bool getData() {
|
||||
REG_RCNT &= ~LINK_PS2_MOUSE_SO_DIRECTION;
|
||||
return (REG_RCNT & LINK_PS2_MOUSE_SO_DATA) >> 1;
|
||||
}
|
||||
|
||||
void setClockHigh() {
|
||||
REG_RCNT |= LINK_PS2_MOUSE_SI_DIRECTION;
|
||||
REG_RCNT |= LINK_PS2_MOUSE_SI_DATA;
|
||||
}
|
||||
|
||||
void setClockLow() {
|
||||
REG_RCNT |= LINK_PS2_MOUSE_SI_DIRECTION;
|
||||
REG_RCNT &= ~LINK_PS2_MOUSE_SI_DATA;
|
||||
}
|
||||
|
||||
void setDataHigh() {
|
||||
REG_RCNT |= LINK_PS2_MOUSE_SO_DIRECTION;
|
||||
REG_RCNT |= LINK_PS2_MOUSE_SO_DATA;
|
||||
}
|
||||
|
||||
void setDataLow() {
|
||||
REG_RCNT |= LINK_PS2_MOUSE_SO_DIRECTION;
|
||||
REG_RCNT &= ~LINK_PS2_MOUSE_SO_DATA;
|
||||
}
|
||||
};
|
||||
|
||||
extern LinkPS2Mouse* linkPS2Mouse;
|
||||
|
||||
#endif // LINK_PS2_MOUSE_H
|
||||
Loading…
Reference in New Issue
Block a user