diff --git a/ppu/include/sysutil/sysutil.h b/ppu/include/sysutil/sysutil.h index cc611248..3cae07e7 100644 --- a/ppu/include/sysutil/sysutil.h +++ b/ppu/include/sysutil/sysutil.h @@ -35,6 +35,8 @@ #define SYSUTIL_OSK_DONE 0x0503 /*! \brief On-screen keyboard has been unloaded. */ #define SYSUTIL_OSK_UNLOADED 0x0504 +/*! \brief On-screen keyboard has canceled input. */ +#define SYSUTIL_OSK_INPUT_CANCELED 0x0506 #ifdef __cplusplus extern "C" { @@ -51,6 +53,7 @@ extern "C" { - \ref SYSUTIL_OSK_LOADED - \ref SYSUTIL_OSK_DONE - \ref SYSUTIL_OSK_UNLOADED + - \ref SYSUTIL_OSK_INPUT_CANCELED \param param Event parameter, depending on event value. \param usrdata Pointer to user data as provided to the \ref sysUtilRegisterCallback function. diff --git a/samples/sys/Makefile b/samples/sys/Makefile index dc76dea1..f776aa82 100644 --- a/samples/sys/Makefile +++ b/samples/sys/Makefile @@ -1,4 +1,4 @@ -TARGETS := msgdialog threadtest +TARGETS := msgdialog osk threadtest all: @for TARGET in $(TARGETS); do $(MAKE) --no-print-directory -C $$TARGET; done diff --git a/samples/sys/osk/Makefile b/samples/sys/osk/Makefile new file mode 100644 index 00000000..c1de0bb9 --- /dev/null +++ b/samples/sys/osk/Makefile @@ -0,0 +1,140 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +TITLE := Osk sample - PSL1GHT +APPID := OSK000001 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -O2 -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lrsx -lgcm_sys -lio -lsysutil -lrt -llv2 -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self + +#--------------------------------------------------------------------------------- +run: + ps3load $(OUTPUT).self + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).self: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .bin extension +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/sys/osk/include/rsxutil.h b/samples/sys/osk/include/rsxutil.h new file mode 100644 index 00000000..cbf41557 --- /dev/null +++ b/samples/sys/osk/include/rsxutil.h @@ -0,0 +1,28 @@ +#ifndef __RSXUTIL_H__ +#define __RSXUTIL_H__ + +#include +#include + +#define CB_SIZE 0x100000 +#define HOST_SIZE (32*1024*1024) + +#ifdef __cplusplus +extern "C" { +#endif + +extern gcmContextData *context; +extern u32 display_width; +extern u32 display_height; +extern u32 curr_fb; + +void set_render_target(u32 index); +void init_screen(void *host_addr,u32 size); +void waitflip(); +void flip(); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/samples/sys/osk/source/main.c b/samples/sys/osk/source/main.c new file mode 100644 index 00000000..7108bd83 --- /dev/null +++ b/samples/sys/osk/source/main.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "rsxutil.h" + +static vs32 dialog_action = 0; + +uint8_t isRunningOSK = 0; +oskInputFieldInfo inputFieldInfo; +oskParam parameters; +oskCallbackReturnParam outputParam; + +static void utf16_to_utf8(const uint16_t *src, uint8_t *dst) +{ + int i; + for (i = 0; src[i]; i++) + { + if ((src[i] & 0xFF80) == 0) + { + *(dst++) = src[i] & 0xFF; + } + else if((src[i] & 0xF800) == 0) + { + *(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0; + *(dst++) = (src[i] & 0x3F) | 0x80; + } + else if((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00) + { + *(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0; + *(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80; + *(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF); + *(dst++) = (src[i + 1] & 0x3F) | 0x80; + i += 1; + } + else + { + *(dst++) = ((src[i] >> 12) & 0xF) | 0xE0; + *(dst++) = ((src[i] >> 6) & 0x3F) | 0x80; + *(dst++) = (src[i] & 0x3F) | 0x80; + } + } + + *dst = '\0'; +} + +static void utf8_to_utf16(const uint8_t *src, uint16_t *dst) +{ + int i; + for (i = 0; src[i];) + { + if ((src[i] & 0xE0) == 0xE0) + { + *(dst++) = ((src[i] & 0x0F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F); + i += 3; + } + else if ((src[i] & 0xC0) == 0xC0) + { + *(dst++) = ((src[i] & 0x1F) << 6) | (src[i + 1] & 0x3F); + i += 2; + } + else + { + *(dst++) = src[i]; + i += 1; + } + } + + *dst = '\0'; +} + +static void do_flip() +{ + sysUtilCheckCallback(); + flip(); +} + +void program_exit_callback() +{ + gcmSetWaitFlip(context); + rsxFinish(context, 1); +} + +void sysutil_exit_callback(u64 status, u64 param, void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + case SYSUTIL_OSK_LOADED: + printf("OSK loaded\n"); + break; + case SYSUTIL_OSK_INPUT_CANCELED: + printf("OSK input canceled\n"); + oskAbort(); + // fall-through + case SYSUTIL_OSK_DONE: + if (status == SYSUTIL_OSK_DONE) + { + printf("OSK done\n"); + } + oskUnloadAsync(&outputParam); + + if (outputParam.res == OSK_OK) + { + printf("OSK result OK\n"); + } + else + { + printf("OKS result: %d\n", outputParam.res); + } + + break; + case SYSUTIL_OSK_UNLOADED: + printf("OSK unloaded\n"); + isRunningOSK = 0; + break; + default: + break; + } +} + +#define TEXT_BUFFER_LENGTH 256 + +int main(int argc,char *argv[]) +{ + void *host_addr = memalign(1024*1024, HOST_SIZE); + static uint16_t title_utf16[TEXT_BUFFER_LENGTH]; + static uint16_t input_text_utf16[TEXT_BUFFER_LENGTH]; + static uint16_t initial_text_utf16[TEXT_BUFFER_LENGTH]; + static uint8_t input_text_utf8[TEXT_BUFFER_LENGTH]; + + // Convert UTF8 to UTF16 + memset(title_utf16, 0, sizeof(title_utf16)); + memset(initial_text_utf16, 0, sizeof(initial_text_utf16)); + utf8_to_utf16((uint8_t *)"Enter your name:", title_utf16); + utf8_to_utf16((uint8_t *)"Sergio", initial_text_utf16); + + printf("osk test...\n"); + + init_screen(host_addr, HOST_SIZE); + ioPadInit(7); + + // Configure the title and initial text of the keyboard, and a maximum length + inputFieldInfo.message = title_utf16; + inputFieldInfo.startText = initial_text_utf16; + inputFieldInfo.maxLength = TEXT_BUFFER_LENGTH - 1; + + // Configure the type of panel + parameters.allowedPanels = OSK_PANEL_TYPE_DEFAULT; + parameters.firstViewPanel = OSK_PANEL_TYPE_DEFAULT; + parameters.controlPoint = (oskPoint) { 0, 0 }; + parameters.prohibitFlags = OSK_PROHIBIT_RETURN; // This will disable entering a new line + + // Configure where the osk will write its result + outputParam.res = OSK_OK; + outputParam.len = TEXT_BUFFER_LENGTH - 1; + outputParam.str = input_text_utf16; + + atexit(program_exit_callback); + + s32 res = 0; + + sys_mem_container_t containerid; + res = sysMemContainerCreate(&containerid, 4 * 1024 * 1024); + if (res != 0) + { + printf("Error sysMemContainerCreate: %08x\n", res); + return 0; + } + + res = sysUtilRegisterCallback(SYSUTIL_EVENT_SLOT0, sysutil_exit_callback, NULL); + if (res != 0) + { + printf("Error sysUtilRegisterCallback: %08x\n", res); + sysMemContainerDestroy(containerid); + return 0; + } + + oskSetInitialInputDevice(OSK_DEVICE_PAD); + oskSetKeyLayoutOption(OSK_FULLKEY_PANEL); + oskSetLayoutMode(OSK_LAYOUTMODE_HORIZONTAL_ALIGN_CENTER | OSK_LAYOUTMODE_VERTICAL_ALIGN_CENTER); + + res = oskLoadAsync(containerid, ¶meters, &inputFieldInfo); + if (res != 0) + { + printf("Error oskLoadAsync: %08x\n", res); + sysUtilUnregisterCallback(SYSUTIL_EVENT_SLOT0); + sysMemContainerDestroy(containerid); + return 0; + } + + printf("Running OSK\n"); + + isRunningOSK = 1; + + while (isRunningOSK) + { + do_flip(); + } + + sysUtilUnregisterCallback(SYSUTIL_EVENT_SLOT0); + sysMemContainerDestroy(containerid); + + if (outputParam.res != OSK_OK) + { + printf("Keyboard cancelled\n"); + return 0; + } + + // Convert UTF16 to UTF8 + utf16_to_utf8(outputParam.str, input_text_utf8); + printf("Hello %s!\n", input_text_utf8); + + sleep(5); + + return 0; +} diff --git a/samples/sys/osk/source/rsxutil.c b/samples/sys/osk/source/rsxutil.c new file mode 100644 index 00000000..b7803e6f --- /dev/null +++ b/samples/sys/osk/source/rsxutil.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include + +#include "rsxutil.h" + +#define GCM_LABEL_INDEX 255 + +videoResolution res; +gcmContextData *context = NULL; + +u32 curr_fb = 0; +u32 first_fb = 1; + +u32 display_width; +u32 display_height; + +u32 depth_pitch; +u32 depth_offset; +u32 *depth_buffer; + +u32 color_pitch; +u32 color_offset[2]; +u32 *color_buffer[2]; + +static u32 sLabelVal = 1; + +static void wait_finish() +{ + rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); + + rsxFlushBuffer(context); + + while(*(vu32*)gcmGetLabelAddress(GCM_LABEL_INDEX)!=sLabelVal) + usleep(30); + + ++sLabelVal; +} + +static void wait_rsx_idle() +{ + rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); + rsxSetWaitLabel(context,GCM_LABEL_INDEX,sLabelVal); + + ++sLabelVal; + + wait_finish(); +} + +void set_render_target(u32 index) +{ + gcmSurface sf; + + sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; + sf.colorTarget = GCM_TF_TARGET_0; + sf.colorLocation[0] = GCM_LOCATION_RSX; + sf.colorOffset[0] = color_offset[index]; + sf.colorPitch[0] = color_pitch; + + sf.colorLocation[1] = GCM_LOCATION_RSX; + sf.colorLocation[2] = GCM_LOCATION_RSX; + sf.colorLocation[3] = GCM_LOCATION_RSX; + sf.colorOffset[1] = 0; + sf.colorOffset[2] = 0; + sf.colorOffset[3] = 0; + sf.colorPitch[1] = 64; + sf.colorPitch[2] = 64; + sf.colorPitch[3] = 64; + + sf.depthFormat = GCM_TF_ZETA_Z16; + sf.depthLocation = GCM_LOCATION_RSX; + sf.depthOffset = depth_offset; + sf.depthPitch = depth_pitch; + + sf.type = GCM_TF_TYPE_LINEAR; + sf.antiAlias = GCM_TF_CENTER_1; + + sf.width = display_width; + sf.height = display_height; + sf.x = 0; + sf.y = 0; + + rsxSetSurface(context,&sf); +} + +void init_screen(void *host_addr,u32 size) +{ + context = rsxInit(CB_SIZE,size,host_addr); + + videoState state; + videoGetState(0,0,&state); + + videoGetResolution(state.displayMode.resolution,&res); + + videoConfiguration vconfig; + memset(&vconfig,0,sizeof(videoConfiguration)); + + vconfig.resolution = state.displayMode.resolution; + vconfig.format = VIDEO_BUFFER_FORMAT_XRGB; + vconfig.pitch = res.width*sizeof(u32); + + wait_rsx_idle(); + + videoConfigure(0,&vconfig,NULL,0); + videoGetState(0,0,&state); + + gcmSetFlipMode(GCM_FLIP_VSYNC); + + display_width = res.width; + display_height = res.height; + + color_pitch = display_width*sizeof(u32); + color_buffer[0] = (u32*)rsxMemalign(64,(display_height*color_pitch)); + color_buffer[1] = (u32*)rsxMemalign(64,(display_height*color_pitch)); + + rsxAddressToOffset(color_buffer[0],&color_offset[0]); + rsxAddressToOffset(color_buffer[1],&color_offset[1]); + + gcmSetDisplayBuffer(0,color_offset[0],color_pitch,display_width,display_height); + gcmSetDisplayBuffer(1,color_offset[1],color_pitch,display_width,display_height); + + depth_pitch = display_width*sizeof(u32); + depth_buffer = (u32*)rsxMemalign(64,(display_height*depth_pitch)*2); + rsxAddressToOffset(depth_buffer,&depth_offset); +} + +void waitflip() +{ + while(gcmGetFlipStatus()!=0) + usleep(200); + gcmResetFlipStatus(); +} + +void flip() +{ + if(!first_fb) waitflip(); + else gcmResetFlipStatus(); + + gcmSetFlip(context,curr_fb); + rsxFlushBuffer(context); + + gcmSetWaitFlip(context); + + curr_fb ^= 1; + set_render_target(curr_fb); + + first_fb = 0; +}