From 662dadd2516133012cd48a6be1f931560e18ab2a Mon Sep 17 00:00:00 2001 From: sato_masaki Date: Fri, 1 Aug 2008 06:11:58 +0000 Subject: [PATCH] =?UTF-8?q?=E6=9C=AC=E4=BD=93=E3=83=87=E3=83=90=E3=83=83?= =?UTF-8?q?=E3=82=B0=E7=94=A8=E7=84=A1=E7=B7=9A=E3=83=81=E3=82=A7=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=83=97=E3=83=AD=E3=82=B0=E3=83=A9=E3=83=A0=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@2071 b08762b0-b915-fc4b-9d8c-17b2551a87ff --- build/tests/WirelessChecker/@ | 1 + build/tests/WirelessChecker/Makefile | 129 ++++++ .../WirelessChecker/banner/000A_WLCK.bmp | Bin 0 -> 630 bytes .../WirelessChecker/banner/000A_WLCK.bsf | Bin 0 -> 982 bytes build/tests/WirelessChecker/banner/Makefile | 47 +++ .../tests/WirelessChecker/components/Makefile | 31 ++ .../components/racoon_wckr/Makefile | 56 +++ .../components/racoon_wckr/make_lsf.pl | 53 +++ .../tests/WirelessChecker/libraries/Makefile | 30 ++ .../libraries/nwm/ARM7/Makefile | 126 ++++++ .../libraries/nwm/ARM9/Makefile | 95 +++++ .../WirelessChecker/libraries/nwm/Makefile | 39 ++ .../libraries/nwm/scripts/Makefile | 42 ++ .../nwm/scripts/make_nwm_fw_wrack.pl | 108 +++++ build/tests/WirelessChecker/readme.txt | 62 +++ .../WirelessChecker/resources/ds_ipl10.bmp | Bin 0 -> 922102 bytes build/tests/WirelessChecker/rsf/Makefile | 37 ++ build/tests/WirelessChecker/rsf/make_rsf.pl | 97 +++++ build/tests/WirelessChecker/src/frame.cpp | 148 +++++++ build/tests/WirelessChecker/src/frame.h | 72 ++++ build/tests/WirelessChecker/src/main.cpp | 135 ++++++ build/tests/WirelessChecker/src/test.cpp | 96 +++++ build/tests/WirelessChecker/src/test.h | 54 +++ .../tests/WirelessChecker/src/test_fatal.cpp | 130 ++++++ build/tests/WirelessChecker/src/test_fatal.h | 37 ++ build/tests/WirelessChecker/src/test_nwm.cpp | 355 ++++++++++++++++ build/tests/WirelessChecker/src/test_nwm.h | 52 +++ .../WirelessChecker/src/test_recovery.cpp | 97 +++++ .../tests/WirelessChecker/src/test_recovery.h | 37 ++ build/tests/WirelessChecker/src/test_wm.cpp | 376 +++++++++++++++++ build/tests/WirelessChecker/src/test_wm.h | 43 ++ .../tests/WirelessChecker/src/util/canvas.cpp | 175 ++++++++ build/tests/WirelessChecker/src/util/canvas.h | 78 ++++ .../tests/WirelessChecker/src/util/memory.cpp | 122 ++++++ build/tests/WirelessChecker/src/util/memory.h | 38 ++ build/tests/WirelessChecker/src/util/util.cpp | 276 +++++++++++++ build/tests/WirelessChecker/src/util/util.h | 103 +++++ .../WirelessChecker/src/util/wprintf.cpp | 387 ++++++++++++++++++ .../tests/WirelessChecker/src/util/wprintf.h | 100 +++++ 39 files changed, 3864 insertions(+) create mode 100644 build/tests/WirelessChecker/@ create mode 100644 build/tests/WirelessChecker/Makefile create mode 100644 build/tests/WirelessChecker/banner/000A_WLCK.bmp create mode 100644 build/tests/WirelessChecker/banner/000A_WLCK.bsf create mode 100644 build/tests/WirelessChecker/banner/Makefile create mode 100644 build/tests/WirelessChecker/components/Makefile create mode 100644 build/tests/WirelessChecker/components/racoon_wckr/Makefile create mode 100755 build/tests/WirelessChecker/components/racoon_wckr/make_lsf.pl create mode 100644 build/tests/WirelessChecker/libraries/Makefile create mode 100644 build/tests/WirelessChecker/libraries/nwm/ARM7/Makefile create mode 100644 build/tests/WirelessChecker/libraries/nwm/ARM9/Makefile create mode 100644 build/tests/WirelessChecker/libraries/nwm/Makefile create mode 100644 build/tests/WirelessChecker/libraries/nwm/scripts/Makefile create mode 100755 build/tests/WirelessChecker/libraries/nwm/scripts/make_nwm_fw_wrack.pl create mode 100644 build/tests/WirelessChecker/readme.txt create mode 100644 build/tests/WirelessChecker/resources/ds_ipl10.bmp create mode 100644 build/tests/WirelessChecker/rsf/Makefile create mode 100755 build/tests/WirelessChecker/rsf/make_rsf.pl create mode 100644 build/tests/WirelessChecker/src/frame.cpp create mode 100644 build/tests/WirelessChecker/src/frame.h create mode 100644 build/tests/WirelessChecker/src/main.cpp create mode 100644 build/tests/WirelessChecker/src/test.cpp create mode 100644 build/tests/WirelessChecker/src/test.h create mode 100644 build/tests/WirelessChecker/src/test_fatal.cpp create mode 100644 build/tests/WirelessChecker/src/test_fatal.h create mode 100644 build/tests/WirelessChecker/src/test_nwm.cpp create mode 100644 build/tests/WirelessChecker/src/test_nwm.h create mode 100644 build/tests/WirelessChecker/src/test_recovery.cpp create mode 100644 build/tests/WirelessChecker/src/test_recovery.h create mode 100644 build/tests/WirelessChecker/src/test_wm.cpp create mode 100644 build/tests/WirelessChecker/src/test_wm.h create mode 100644 build/tests/WirelessChecker/src/util/canvas.cpp create mode 100644 build/tests/WirelessChecker/src/util/canvas.h create mode 100644 build/tests/WirelessChecker/src/util/memory.cpp create mode 100644 build/tests/WirelessChecker/src/util/memory.h create mode 100644 build/tests/WirelessChecker/src/util/util.cpp create mode 100644 build/tests/WirelessChecker/src/util/util.h create mode 100644 build/tests/WirelessChecker/src/util/wprintf.cpp create mode 100644 build/tests/WirelessChecker/src/util/wprintf.h diff --git a/build/tests/WirelessChecker/@ b/build/tests/WirelessChecker/@ new file mode 100644 index 00000000..bd33deb9 --- /dev/null +++ b/build/tests/WirelessChecker/@ @@ -0,0 +1 @@ +NINTENDO_RED_CONFIDENTIAL diff --git a/build/tests/WirelessChecker/Makefile b/build/tests/WirelessChecker/Makefile new file mode 100644 index 00000000..bb75e662 --- /dev/null +++ b/build/tests/WirelessChecker/Makefile @@ -0,0 +1,129 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlSDK - tools - Wireless Checker +# File: Makefile +# +# Copyright 2008 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +override TARGET_PLATFORM = TWL +override TWL_CODEGEN = ARM +override TWL_ARCHGEN = LIMITED + +SUBDIRS = libraries components rsf banner + +RES_DIR = ./resources + +SRCDIR = src +INCDIR = include $(ROOT)/build/libraries/wm/common.TWL/inc \ + $(ROOT)/build/libraries/wm/ARM9.TWL/nwm/inc + +ifeq ($(TWL_NANDAPP),TRUE) +ROM_SPEC = rsf/wireless_checker_nand.rsf +else +ROM_SPEC = rsf/wireless_checker.rsf +endif + +BANNER_FILE = ./banner/000A_WLCK.bnr +MAKEROM_FLAGS = -DBANNER_FILE='$(BANNER_FILE)' + +#---------------------------------- +# Font + +FONTCVTR_DIR = $(call empath,$(TWLSYSTEM_ROOT))/tools/fontcvtr +FONT_BMP = $(RES_DIR)/ds_ipl10.bmp + +TARGET_OBJ += $(FONT_O) +EXT_OBJS += $(OBJDIR)/$(FONT_O) + + +FONT_RES_LC = $(RES_DIR)/font.NFTR +FONT_O_LC = font.o + +FONT_RES = $(FONT_RES_LC) +FONT_O = $(FONT_O_LC) + +MACRO_FLAGS += -DTWLNMENU_USE_LC_FONT + + +LDIRT_CLEAN += $(FONT_RES_LC) $(FONT_RES_NO_LC) *.rsf $(REVISION_C) + +#---------------------------------------------------------------------------- + +ifeq ($(TWL_NANDAPP),TRUE) +TARGET_BIN = WirelessChecker.tad +else +TARGET_BIN = WirelessChecker.srl +endif + +SRCS = main.cpp \ + frame.cpp \ + test.cpp \ + test_wm.cpp \ + test_nwm.cpp \ + test_fatal.cpp \ + test_recovery.cpp \ + util/util.cpp \ + util/canvas.cpp \ + util/wprintf.cpp \ + util/memory.cpp + +LINCLUDES = $(ROOT)/build/libraries/wm/ARM9.TWL/nwm/inc \ + $(ROOT)/build/libraries/wm/common.TWL/inc + +LLIBRARY_DIRS = +LLIBRARIES = + +COMPONENT_NAME = racoon +MAKEROM_ARM7_BASE = ./components/racoon_wckr/bin/$(TWL_BUILDTYPE_ARM7)/racoon +MAKEROM_ARM7 = $(MAKEROM_ARM7_BASE).$(TWL_ELF_EXT) + +include $(TWLSYSTEM_ROOT)/build/buildtools/commondefs +include $(TWLSDK_ROOT)/build/buildtools/twl/commondefs.add-ins.nadk + +LIBRARIES_UNLINK := libnwm$(TWL_LIBSUFFIX).a + +LLIBRARY_DIRS += ./libraries/nwm/ARM9/lib/$(TWL_BUILDTYPE_ARM9) +LLIBRARIES += libnwm.WCKR$(TWL_LIBSUFFIX).a + +#---------------------------------------------------------------------------- + +# convert font + +$(FONT_RES): $(FONT_BMP) $(FONT_FILTER) +ifdef SILENT + echo "make font:" $(notdir $<) +endif + $(FONTCVTR_DIR)/fontcvtrc.exe \ + -i bmp -if $< -io $(FONTCVTR_DIR)/xlor/ds_ipl.xlor -ib 1 \ + -o nitro -of $@ -oe utf16 -oa 0x23 $(FONT_OPTION) + +$(OBJDIR)/$(FONT_O): $(FONT_RES) +ifdef SILENT + echo " b2o font:" $(notdir $<) +endif + $(BIN2OBJ) $< $@ --begin font_NFTR_begin --end font_NFTR_end --align 32 + +INSTALL_TARGETS = $(BINDIR)/$(TARGET_BIN) +INSTALL_DIR = ./ +#$(TWLSDK_INSTALL_ROOT)/bin/$(CODEGEN_PROC)-$(TWL_PLATFORM)/$(TWL_BUILD_DIR) + +do-build: $(TARGETS) +ifneq ($(TWL_NANDAPP),TRUE) + $(REMAKE) TWL_NANDAPP=TRUE SKIP_SUBDIR=TRUE +endif + +include $(TWLSYSTEM_ROOT)/build/buildtools/modulerules +include $(TWLSDK_ROOT)/build/buildtools/twl/modulerules.add-ins.nadk + +#===== End of Makefile ===== diff --git a/build/tests/WirelessChecker/banner/000A_WLCK.bmp b/build/tests/WirelessChecker/banner/000A_WLCK.bmp new file mode 100644 index 0000000000000000000000000000000000000000..51252b83b8943e0a1e79119cf95de67d5188ea13 GIT binary patch literal 630 zcmd5&yA1*{3^j-W7=e;4PC`ye7uRfYE!l*QHE_)gNUXpH;n^`FN0$!gUi^D@&ORLH zHMz{V_rNZ&q7AI2Y{M<3gjI>!2VKd+s!IA$dfl%yO()!Cn335p zsDzUfG^B-*vUukU-g1_gMc%6VdZ&Q+=|B2^|Hj8034{AMwjbMo&1`Dvi-6bVzk6x? PU!QHC);Rh%e{lXc5>BI@ literal 0 HcmV?d00001 diff --git a/build/tests/WirelessChecker/banner/000A_WLCK.bsf b/build/tests/WirelessChecker/banner/000A_WLCK.bsf new file mode 100644 index 0000000000000000000000000000000000000000..a8d31c5b491b015fa7ba43f623f9ed2fcd6f4c17 GIT binary patch literal 982 zcmbtTJ5Iwu5PdZgcd(KMq<}`EqXWw}CI}Elp^QRgj3tO8l9~hL5LBE14nPaHprPUl z2zWEg2DyM{HS%hAKJU%XU!PsIRN(nycG4vv_O+DgoLcA#2kSL-3NmUZ2D6%C8K zh40BeEBLEY_0gQ1_#E2Wx3X6`w1kWyND2E|vBsL!Tw1OvPJ$3q?n6n`@ef{xBnU6F z{n0&{SbjN9gYa@rZDbXD#3FDSy8DXt+rv0;DlvOk6H#}}{YiU)h<$Fd&c)ZP`}7T8 C{Dh1E literal 0 HcmV?d00001 diff --git a/build/tests/WirelessChecker/banner/Makefile b/build/tests/WirelessChecker/banner/Makefile new file mode 100644 index 00000000..f6ef1ca6 --- /dev/null +++ b/build/tests/WirelessChecker/banner/Makefile @@ -0,0 +1,47 @@ +#! make -f +#--------------------------------------------------------------------------- +# Project: NitroSDK - tools +# File: Makefile +# +# Copyright 2003,2004 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: Makefile,v $ +# Revision 1.1 2004/11/01 08:25:59 ooe +# (none) +# +# $NoKeywords: $ +#--------------------------------------------------------------------------- + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +BANNER_ICON = 000A_WLCK.bmp +BANNER_SPEC = 000A_WLCK.bsf + +TARGETS = $(BANNER_SPEC:.bsf=.bnr) + +BANNER_ICON_NAME = $(basename $(BANNER_ICON)) + +LDIRT_CLEAN = $(TARGETS) \ + $(BANNER_ICON_NAME).nbfs \ + $(BANNER_ICON_NAME).nbfc \ + $(BANNER_ICON_NAME).nbfp \ + $(TARGETS:.bnr=.srl) + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + + +#---------------------------------------------------------------------------- +# build +#---------------------------------------------------------------------------- +do-build: $(TARGETS) + +$(TARGETS): $(BANNER_SPEC) $(BANNER_ICON_NAME).nbfc $(BANNER_ICON_NAME).nbfp + $(MAKEBANNER) -N $(BANNER_ICON_NAME) $(BANNER_SPEC) $(TARGETS) + +# diff --git a/build/tests/WirelessChecker/components/Makefile b/build/tests/WirelessChecker/components/Makefile new file mode 100644 index 00000000..6ca34f03 --- /dev/null +++ b/build/tests/WirelessChecker/components/Makefile @@ -0,0 +1,31 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TWL WLAN - components +# File: Makefile +# +# Copyright 2003 - 2008 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: Makefile,v $ +# +# +# $NoKeywords: $ +#---------------------------------------------------------------------------- + + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +#---------------------------------------------------------------------------- + +SUBDIRS_P += racoon_wckr + +#---------------------------------------------------------------------------- + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + +#===== End of Makefile ===== diff --git a/build/tests/WirelessChecker/components/racoon_wckr/Makefile b/build/tests/WirelessChecker/components/racoon_wckr/Makefile new file mode 100644 index 00000000..81bcb35e --- /dev/null +++ b/build/tests/WirelessChecker/components/racoon_wckr/Makefile @@ -0,0 +1,56 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlSDK - components - racoon.TWL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +# Definition to override for racoon_wckr +# + +LLIBRARIES += libnwm_sp.WCKR$(TWL_LIBSUFFIX).a +LLIBRARY_DIRS += ../../libraries/nwm/ARM7/lib/$(TWL_BUILDTYPE) + +COMPONENT_DIR += $(ROOT)/build/components/racoon.TWL +COMPONENT_SRC_DIR += $(ROOT)/build/components/mongoose.TWL/src + +override SRCS = $(COMPONENT_SRC_DIR)/main.c $(COMPONENT_SRC_DIR)/initScfg.c + +override TARGET_NAME = racoon + +# Generate my own lsf from original lsf of mongoose +LSF_ORG = $(COMPONENT_DIR)/$(TARGET_NAME).lsf +MAKE_LSF = make_lsf.pl +AUTOGEN_LSF = $(TARGET_NAME)_wckr.lsf + +LDIRT_CLEAN = $(AUTOGEN_LSF) + +override TARGET_NEF = $(TARGET_NAME).tef +override LCFILE_SPEC = $(AUTOGEN_LSF) +override LCFILE_TEMPLATE = $(COMPONENT_DIR)/$(TARGET_NAME).lcf.template +override LDRES_TEMPLATE = $(COMPONENT_DIR)/$(TARGET_NAME).response.template + +override TWL_INSTALL_COMPONENTSDIR= +override INSTALL_TARGETS = +override INSTALL_DIR = + +# + +include $(TWLSDK_ROOT)/build/components/racoon.TWL/Makefile + +$(AUTOGEN_LSF): $(LSF_ORG) $(MAKE_LSF) + @echo " make:" $@ + @perl $(MAKE_LSF) $(TARGET_NAME) + +#===== End of Makefile ===== diff --git a/build/tests/WirelessChecker/components/racoon_wckr/make_lsf.pl b/build/tests/WirelessChecker/components/racoon_wckr/make_lsf.pl new file mode 100755 index 00000000..b3c48384 --- /dev/null +++ b/build/tests/WirelessChecker/components/racoon_wckr/make_lsf.pl @@ -0,0 +1,53 @@ +#!/bin/perl +#---------------------------------------------------------------------------- +# Project: TwlWLAN - components - mongoose_sdlog.TWL +# File: make_lsf.pl +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +use strict; + +my $ROOT; + +my $COMPONENT = $ARGV[0]; +print $COMPONENT; +# search TWLSDK_ROOT +foreach ( sort keys ( %ENV ) ){ + if ($_ =~ m/TWLSDK_ROOT/s) { + $ROOT = $ENV{$_}; + } +} + +my $src = sprintf("$ROOT/build/components/%s.TWL/%s.lsf", $COMPONENT, $COMPONENT); +my $dst = sprintf("%s_wckr.lsf", $COMPONENT); + + +my $rn = "\x0D\x0A"; + +open(F, $src) or die "cant open $src\n"; +my @lines = ; +close(F); + + +open(OUT, ">$dst") or die "cant open $dst\n"; +foreach my $line ( @lines ) +{ + if( $line =~ m/libnwm_sp/ ) + { + $line =~ s/libnwm_sp/libnwm_sp\.WCKR/; + } + + print OUT $line; +} +close(OUT); diff --git a/build/tests/WirelessChecker/libraries/Makefile b/build/tests/WirelessChecker/libraries/Makefile new file mode 100644 index 00000000..401e4ee5 --- /dev/null +++ b/build/tests/WirelessChecker/libraries/Makefile @@ -0,0 +1,30 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +#---------------------------------------------------------------------------- + +SUBDIRS = nwm + +#---------------------------------------------------------------------------- + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + + +#===== End of Makefile ===== diff --git a/build/tests/WirelessChecker/libraries/nwm/ARM7/Makefile b/build/tests/WirelessChecker/libraries/nwm/ARM7/Makefile new file mode 100644 index 00000000..fb996b9d --- /dev/null +++ b/build/tests/WirelessChecker/libraries/nwm/ARM7/Makefile @@ -0,0 +1,126 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlSDK - WM - libraries +# File: Makefile +# +# Copyright 2003 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +SUBDIRS = + +#---------------------------------------------------------------------------- +override TARGET_PLATFORM = TWL + +# Codegen for sub processer +TWL_PROC = ARM7 + +# build ARM & THUMB libraries +TWL_CODEGEN ?= ALL + +MACRO_FLAGS = -DNWM_WRACK_FIRMWARE + +NWM_SRCDIR = $(ROOT)/build/libraries/wm/ARM7.TWL/nwm + +#---------------------------------------------------------------------------- + +# INCDIR 注意点: +INCDIR = $(NWM_SRCDIR)/inc $(NWM_SRCDIR)/../../inc \ + $(NWM_SRCDIR)/../../ARM7/inc $(NWM_SRCDIR)/../../common.TWL/inc \ + $(NWM_SRCDIR)/../common/inc \ + $(NWM_SRCDIR)/../../../wpa/include \ + $(TWLWIRELESS_ROOT)/include \ + $(TWLWIRELESS_ROOT)/host/include \ + $(TWLWIRELESS_ROOT)/host/wlan/include \ + $(TWLWIRELESS_ROOT)/host/os/twl/include \ + $(TWLWIRELESS_ROOT)/host/os/twl/library/athioctl/include \ + $(TWLWIRELESS_ROOT)/host/os/nitro/include \ + $(TWLWIRELESS_ROOT)/host/os/nitro/library/athioctl/include \ + $(ROOT)/build/libraries/spi/ARM7/include + +SRCDIR_ = ../../ARM7/src src ../../common.TWL/src + +SRCDIR = $(addprefix $(NWM_SRCDIR)/, $(SRCDIR_)) + +SRCS_ARM7 = nwmsp_system.c \ + nwmsp_cmd.c \ + nwmsp_event.c \ + nwmsp_wlan_handler.c \ + nwmsp_event_handler.c \ + nwmsp_beaconinfo.c + +SRCS_COMMON = nwm_loaddev.c \ + nwm_unloaddev.c \ + nwm_open.c \ + nwm_close.c \ + nwm_startscan.c \ + nwm_connect.c \ + nwm_disconnect.c \ + nwm_sendframe.c \ + nwm_recvframe.c \ + nwm_setwepkey.c \ + nwm_setpowersave.c \ + nwm_wpa.c \ + nwm_qos.c \ + nwm_reset.c + +SRCS = $(addprefix $(NWM_SRCDIR)/src/, $(SRCS_ARM7)) \ + $(addprefix $(NWM_SRCDIR)/../../common.TWL/src/, $(SRCS_COMMON)) \ + ../src/nwm_installfirm_autogen.c + +TARGET_LIB = libnwm_sp.WCKR$(TWL_LIBSUFFIX).a + +#---------------------------------------------------------------------------- + +# DEBUG版ビルドの場合、RELEASE版でビルドして +# DEBUG版のライブラリを装います。 + +ifdef TARGET_DEBUG +TWL_BUILD_TYPE = RELEASE +else +ifdef TWL_DEBUG +TWL_BUILD_TYPE = RELEASE +CCFLAGS += -DNWM_DEBUG +else +ifdef NITRO_DEBUG +TWL_BUILD_TYPE = RELEASE +endif +endif +endif + +#---------------------------------------------------------------------------- +# Default では LIMITED のライブラリを作成します +TWL_ARCHGEN ?= LIMITED + +#---------------------------------------------------------------------------- + +# 新無線用のデバッグフラグなど + +ifdef NWM_DEBUG +CCFLAGS += -DNWM_DEBUG +endif + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +#INSTALL_TARGETS = $(TARGETS) +#INSTALL_DIR = $(SYSMENU_INSTALL_LIBDIR) +#GDIRT_INSTALLED = $(addprefix $(INSTALL_DIR)/,$(notdir $(INSTALL_TARGETS))) + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + + +#===== End of Makefile ===== + diff --git a/build/tests/WirelessChecker/libraries/nwm/ARM9/Makefile b/build/tests/WirelessChecker/libraries/nwm/ARM9/Makefile new file mode 100644 index 00000000..aa35f646 --- /dev/null +++ b/build/tests/WirelessChecker/libraries/nwm/ARM9/Makefile @@ -0,0 +1,95 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlSDK - WM - libraries +# File: Makefile +# +# Copyright 2003 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- +#SUBDIRS = wm_lib + +override TARGET_PLATFORM = TWL + +# Codegen for sub processer +TWL_PROC = ARM9 +TWL_CODEGEN ?= ALL + +MACRO_FLAGS = -DNWM_WRACK_FIRMWARE + +NWM_SRCDIR = $(ROOT)/build/libraries/wm/ARM9.TWL/nwm + +# HYBRID / LIMITED 両方のライブラリを作成します +TWL_ARCHGEN ?= ALL + +# LoadDeviceEx で転送するファームウェアのディレクトリ +TWLWIRELESS_FW_DIR = $(ROOT)/add-ins/TwlWireless/$(TWLWIRELESS_PACKAGE)/binfile + +SRCDIR = ./src ../../common.TWL/src +INCDIR = $(NWM_SRCDIR)/inc $(NWM_SRCDIR)/../../inc $(NWM_SRCDIR)/../../ARM9/inc \ + $(NWM_SRCDIR)/../../common.TWL/inc $(NWM_SRCDIR)/../common/inc + +SRCS_ARM9 = nwm_init.c \ + nwm_system.c \ + nwm_end.c \ + nwm_cmd.c \ + nwm_passphrase.c + +SRCS_COMMON = nwm_loaddev.c \ + nwm_unloaddev.c \ + nwm_open.c \ + nwm_close.c \ + nwm_startscan.c \ + nwm_connect.c \ + nwm_disconnect.c \ + nwm_setwepkey.c \ + nwm_setpowersave.c \ + nwm_sendframe.c \ + nwm_recvframe.c \ + nwm_wpa.c \ + nwm_qos.c \ + nwm_reset.c + +SRCS = $(addprefix $(NWM_SRCDIR)/src/, $(SRCS_ARM9)) \ + $(addprefix $(NWM_SRCDIR)/../../common.TWL/src/, $(SRCS_COMMON)) \ + ../src/nwm_installfirm_autogen.c + +EXT_OBJS = $(OBJDIR)/nwm_firm.o + +TARGET_LIB = libnwm.WCKR$(TWL_LIBSUFFIX).a + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +#INSTALL_TARGETS = $(TARGETS) + +#INSTALL_DIR = $(TWL_INSTALL_LIBDIR) + +GDIRT_INSTALLED = $(addprefix $(INSTALL_DIR)/,$(notdir $(INSTALL_TARGETS))) + +#---------------------------------------------------------------------------- +# 新無線用のデバッグフラグなど + +ifdef NWM_DEBUG +CCFLAGS += -DNWM_DEBUG +endif + +CCFLAGS += -DENABLE_RXACK + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + +$(OBJDIR)/nwm_firm.o: $(TWLWIRELESS_FW_DIR)/nwm_firm.bin + $(BIN2OBJ) $(call empath, $<) $@ + +#===== End of Makefile ===== diff --git a/build/tests/WirelessChecker/libraries/nwm/Makefile b/build/tests/WirelessChecker/libraries/nwm/Makefile new file mode 100644 index 00000000..a7c14231 --- /dev/null +++ b/build/tests/WirelessChecker/libraries/nwm/Makefile @@ -0,0 +1,39 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlSDK - libraries - wm +# File: Makefile +# +# Copyright 2003 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + + +TARGET_PLATFORM := TWL + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +#---------------------------------------------------------------------------- + +SUBDIRS = scripts + +ifneq ($(filter TWL,$(TARGET_PLATFORM_LIST)),) +SUBDIRS_P += ARM9 +ifeq ($(TWLSDK_PRIVATE),TRUE) +SUBDIRS_P += ARM7 +endif +endif + +#---------------------------------------------------------------------------- + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + +#===== End of Makefile ===== diff --git a/build/tests/WirelessChecker/libraries/nwm/scripts/Makefile b/build/tests/WirelessChecker/libraries/nwm/scripts/Makefile new file mode 100644 index 00000000..23d56e70 --- /dev/null +++ b/build/tests/WirelessChecker/libraries/nwm/scripts/Makefile @@ -0,0 +1,42 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlSDK - libraries - wm +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +override TWL_CODEGEN := ARM +override TWL_ARCHGEN := LIMITED + +NWM_ORG = $(ROOT)/build/libraries/wm/common.TWL/src/nwm_installfirm.c +MAKE_NWM = make_nwm_fw_wrack.pl +AUTOGEN_NWM = src/nwm_installfirm_autogen.c +LDIRT_CLEAN += $(AUTOGEN_NWM) + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +#---------------------------------------------------------------------------- + +TARGETS = $(AUTOGEN_NWM) + +#---------------------------------------------------------------------------- +do-build: $(TARGETS) + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + +$(AUTOGEN_NWM): $(NWM_ORG) $(MAKE_NWM) + @echo " make:" $@ + @perl $(MAKE_NWM) + +#===== End of Makefile ===== diff --git a/build/tests/WirelessChecker/libraries/nwm/scripts/make_nwm_fw_wrack.pl b/build/tests/WirelessChecker/libraries/nwm/scripts/make_nwm_fw_wrack.pl new file mode 100755 index 00000000..50d2ebf4 --- /dev/null +++ b/build/tests/WirelessChecker/libraries/nwm/scripts/make_nwm_fw_wrack.pl @@ -0,0 +1,108 @@ +#!/bin/perl +#---------------------------------------------------------------------------- +# Project: TwlIPL - tests - +# File: make_nwm_fw_wrack.pl +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- + +use strict; + +my $rn = "\x0D\x0A"; + +my $SDKROOT; + +# search TWLSDK_ROOT +foreach ( sort keys ( %ENV ) ){ + if ($_ =~ m/TWLSDK_ROOT/s) { + $SDKROOT = $ENV{$_}; + } +} + +my $src = "$SDKROOT/build/libraries/wm/common.TWL/src/nwm_installfirm.c"; +my $dst_dir = "../src"; +my $dst_file = "nwm_installfirm_autogen.c"; + +open(F, $src) or die "cant open $src\n"; +my @lines = ; +close(F); + +mkdir $dst_dir unless -e $dst_dir; + +my $in_instfirm_count = 0; + +open(OUT, ">$dst_dir/$dst_file") or die "cant open $dst_dir/$dst_file\n"; +foreach my $line ( @lines ) +{ + if ( $line =~ m/^NWMRetCode NWMi_InstallFirmware\(NWMCallbackFunc callback, void\* addr, u32 size, BOOL isColdstart\)/ ) + { + print OUT <<__WRACK_FIRMWARE_API__; + +\#ifdef NWM_WRACK_FIRMWARE +NWMRetCode NWMi_WrackFirmware(NWMCallbackFunc callback); + +NWMRetCode NWMi_WrackFirmware(NWMCallbackFunc callback) +{ + NWMArm9Buf *sys = NWMi_GetSystemWork(); + NWMRetCode result; + + // コールバック関数を登録 + NWMi_SetCallbackTable(NWM_APIID_INSTALL_FIRMWARE, callback); + + // ARM7にFIFOで通知 + result = NWMi_SendCommand(NWM_APIID_INSTALL_FIRMWARE, 5, + (u32)(sys->NWM7), (u32)(sys->status), (u32)(sys->fifo7to9), NULL, FALSE); + + return NWM_RETCODE_OPERATING; +} +\#endif // NWM_WRACK_FIRMWARE + +__WRACK_FIRMWARE_API__ + } + + if ( $line =~ m/MCU_SetWifiLedBlinkingStatus\( FALSE \);/ ) + { + print OUT "#ifndef NWM_WRACK_FIRMWARE", $rn; + } + + if( $line =~ m/^installfirm_err:/ ) + { + print OUT <<__WRACK_FIRMWARE__; + +\#else // NWM_WRACK_FIRMWARE +\#pragma unused (err) + // set WiFi_RST to disable WiFi + NWMSPi_SetWiFiReset(FALSE); + OS_Sleep(1); // wait 1msec + // set WiFi_RST to enable WiFi + NWMSPi_SetWiFiReset(TRUE); + { + NWMCallback *cb; + + NWMSP_ClearAPIActiveFlag(NWM_APIID_INSTALL_FIRMWARE); + // 正常終了 + cb = (NWMCallback *)NWMSP_GetBuffer4Callback2Nwm9(); + cb->apiid = NWM_APIID_INSTALL_FIRMWARE; + cb->retcode = NWM_RETCODE_FATAL_ERROR; + NWMSP_ReturnResult2Nwm9((void *)cb); + return; + } +\#endif // NWM_WRACK_FIRMWARE +__WRACK_FIRMWARE__ + } + print OUT $line; + + +} +close(OUT); + diff --git a/build/tests/WirelessChecker/readme.txt b/build/tests/WirelessChecker/readme.txt new file mode 100644 index 00000000..980f4e29 --- /dev/null +++ b/build/tests/WirelessChecker/readme.txt @@ -0,0 +1,62 @@ +* WirelessChecker - 本体デバッグ用 無線機能チェックプログラム + +- 確認手順 + +1. 本体無線フラグの確認 + + 上画面の「無線ON/OFF設定」および「無線強制OFF本体」の設定を確認してください。 + 無線が使用できる状態は、以下の状態です。 + + 無線ON/OFF設定[ON ] + 無線強制OFF本体[No ] + + +2. DS無線の初期化テスト + + DS無線の初期化→スキャン→終了をテストします。 + アクティブスキャン(電波を出すスキャン)を行います。 + LEDの点滅を確認することで無線が正常に動作していることを確認してください。 + また、無線ON/OFF設定をOFFにすることで、初期化が失敗することを確認してください。 + +3. TWL無線の初期化テスト + + TWL無線の初期化→スキャン→終了をテストします。 + アクティブスキャン(電波を出すスキャン)を行います。 + LEDの点滅を確認することで無線が正常に動作していることを確認してください。 + また、無線ON/OFF設定をOFFにすることで、初期化が失敗することを確認してください。 + +4. FATALエラーリカバリテスト + + TWL無線モジュールのファームウェア壊れをエミュレートし、それによるFATALエラー発生後、 + アプリジャンプによるハードウェアリセットで、ファームウェアがロードし直されていることを確認します。 + 再起動後に自動的にTWL無線の初期化チェックを行います。初期化チェックが成功し、LEDが点滅していることを確認してください。 + +(以下の項目はオプションです。) + +5. FATALエラーエミュレーション + 項目4.のFATALエラーを手動で起こします。この操作を行った後、「TWL無線の初期化テスト」が失敗することを確認してください。 + + +- TODO + +・NOAとかのデバッグにむけて英語表示も対応(?) + +- 変更履歴 + +- 080801 + NANDアプリに対応。 + バナー追加。 + ゲームコード追加。 + +- 080731 + FINALROMでビルド。 + テスト用のプリントデバッグが出ていたのを修正。 + コマンドログを日本語化。 + TwlSDK 5.0 RC1でビルド。 + +- 080730 + 下画面に簡易ヘルプを表示。 + +- 080725 + 最初のリリース + diff --git a/build/tests/WirelessChecker/resources/ds_ipl10.bmp b/build/tests/WirelessChecker/resources/ds_ipl10.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6fc8eedc4107a86244e2b3a56e2555d3588b880f GIT binary patch literal 922102 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

jXZKPw%h35 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 z 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 +close(F); + + +open(OUT, ">$dst1") or die "cant open $dst1\n"; +foreach my $line ( @lines ) +{ + if( $line =~ m/TitleName\t+/ ) + { + $line =~ s/\t\#?TitleName.*\".*\"/\tTitleName\t\t\"WLAN CHECKER\"/; + } + + if( $line =~ m/^\tBannerFile/ ) + { + print OUT "\tBannerFile\t\t\$(BANNER_FILE)", $rn; + print OUT $rn, "\t#", $rn; + print OUT "\t# Permit LandingNormalJump: for TWL \"ApplicationJump\" function [TRUE/FALSE]", $rn; + print OUT "\t#", $rn; + print OUT "\tPermitLandingNormalJump\tTRUE", $rn; + next; + } + + print OUT $line; +} +close(OUT); + + +my $src2 = "$ROOT/include/twl/specfiles/ROM-TS_nand.rsf"; +my $dst2 = "wireless_checker_nand.rsf"; + +open(F, $src2) or die "cant open $src2\n"; +my @lines = ; +close(F); + + +open(OUT, ">$dst2") or die "cant open $dst2\n"; +foreach my $line ( @lines ) +{ + if( $line =~ m/^\tBannerFile/ ) + { + print OUT "\tBannerFile\t\t\$(BANNER_FILE)", $rn; + next; + } + + if( $line =~ m/GameCode\t+/ ) + { + $line =~ s/\t\#?GameCode.*[a-zA-Z0-9]{4}/\tGameCode\t\t\t\t000A/; + } + + if( $line =~ m/TitleName\t+/ ) + { + $line =~ s/\t\#?TitleName.*\".*\"/\tTitleName\t\t\"WLAN CHECKER\"/; + } + + if( $line =~ m/PermitLandingNormalJump/ ) + { + $line =~ s/\t\#?.*(TRUE|FALSE)/\tPermitLandingNormalJump\tTRUE/; + } + + print OUT $line; +} \ No newline at end of file diff --git a/build/tests/WirelessChecker/src/frame.cpp b/build/tests/WirelessChecker/src/frame.cpp new file mode 100644 index 00000000..c8582dc0 --- /dev/null +++ b/build/tests/WirelessChecker/src/frame.cpp @@ -0,0 +1,148 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checker + File: main.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "util/util.h" +#include "util/canvas.h" +#include "frame.h" + +namespace +{ + +} + +CFrame::CFrame() : m_itemIndex(ITEM_TEST_WM) +{ + OS_InitMessageQueue(&m_EntrMsgq, m_EntrMsg, sizeof(m_EntrMsg)/sizeof(m_EntrMsg[0])); + +} + +CFrame::CFrame(u8 item) +{ + m_itemIndex = item; + OS_InitMessageQueue(&m_EntrMsgq, m_EntrMsg, sizeof(m_EntrMsg)/sizeof(m_EntrMsg[0])); +} + +CFrame::~CFrame() +{ + +} + +void +CFrame::InitDisp() +{ + util::CCanvas* pcm = util::GetMain1Canvas(); + util::CCanvas* pcs = util::GetSub1Canvas(); + + pcm->Clear(util::COLOR_BLACK); + pcs->Clear(util::COLOR_BLACK); + pcm->Printf(16*5, 0, util::COLOR_WHITE, L"無線機能確認ツール"); + pcm->Printf(96, 16*1, util::COLOR_WHITE, L"BUILD TIME: %s %s", L""__DATE__, L""__TIME__); + + DrawBorder(pcm, 4, 16*2 + 4, 256 - 8, 192 - (16*2 + 4), util::COLOR_WHITE); + pcm->Printf(16*1, 16*3, util::COLOR_WHITE, L"無線ON/OFF設定[ %s ]", TRUE == OS_IsAvailableWireless() ? L"ON ":L"OFF"); + pcm->Printf(16*8, 16*3, util::COLOR_WHITE, L"無線強制OFF本体[ %s ]", TRUE == OS_IsForceDisableWireless() ? L"Yes":L"No "); + + pcm->Printf(16*2, 16*5, util::COLOR_WHITE, L"DS無線の初期化テスト"); + pcm->Printf(16*2, 16*6, util::COLOR_WHITE, L"TWL無線の初期化テスト"); + pcm->Printf(16*2, 16*7, util::COLOR_WHITE, L"FATALエラーエミュレーション"); + pcm->Printf(16*2, 16*8, util::COLOR_WHITE, L"FATALエラーリカバリテスト"); + + DrawBorder(pcs, 4, 16*9 + 4, 256 - 8, 192 - (16*9 + 4), util::COLOR_WHITE); +} + +void +CFrame::CursorDisp(int xpos, int ystart, util::PaletteColor color) +{ + util::CCanvas* pcm = util::GetMain1Canvas(); + pcm->Clear(xpos, ystart, 16, 16*ITEM_NUM, util::COLOR_BLACK); + pcm->Print(xpos, ystart + 16*GetItemIndex(), color, L"■"); +} + +void +CFrame::HelpDisp(util::PaletteColor color) +{ + util::CCanvas* pcs = util::GetSub1Canvas(); + pcs->Clear(8, 16*9 + 8, 256 - 16, 16*2, util::COLOR_BLACK); + + wchar_t *pHelpString1, *pHelpString2; + + switch (GetItemIndex()) + { + case ITEM_TEST_WM: + pHelpString1 = L"DS無線の初期化テストを行います。"; + pHelpString2 = L"LEDの点滅を確認してください。"; + break; + case ITEM_TEST_NWM: + pHelpString1 = L"TWL無線の初期化テストを行います。"; + pHelpString2 = L"LEDの点滅を確認してください。"; + break; + case ITEM_TEST_FATAL: + pHelpString1 = L"FATALエラーを発生させ、TWL無線を使えなくします"; + pHelpString2 = L"HWリセットで回復します。"; + break; + case ITEM_TEST_RECOVERY: + pHelpString1 = L"FATALエラーのリカバリーをテストします。"; + pHelpString2 = L"再起動後にTWL無線初期化を確認してください。"; + break; + } + pcs->Print(8, 16*9 + 8, color, pHelpString1); + pcs->Print(8, 16*10 + 8, color, pHelpString2); +} + +BOOL +CFrame::AutoEnter() +{ + return OS_SendMessage(&m_EntrMsgq, (OSMessage)TRUE, OS_MESSAGE_NOBLOCK); +} + +void +CFrame::ProcessButton() +{ + if (util::IsPadTrigger(PAD_KEY_UP)) + { + decRound(); + } else + if (util::IsPadTrigger(PAD_KEY_DOWN)) + { + incRound(); + } + + if (util::IsPadTrigger(PAD_BUTTON_A)) + { + if (FALSE == OS_SendMessage(&m_EntrMsgq, (OSMessage)TRUE, OS_MESSAGE_NOBLOCK)) + { + // already entered + } + } +} + +BOOL +CFrame::IsEnter() +{ + OSMessage msg; + return OS_ReceiveMessage(&m_EntrMsgq, &msg, OS_MESSAGE_NOBLOCK); + +} + +void +CFrame::DrawBorder(util::CCanvas* pCanvas, int px, int py, int pw, int ph, util::PaletteColor color) +{ + pCanvas->Clear(px, py, pw, 1, color); + pCanvas->Clear(px, py + ph - 1, pw, 1, color); + pCanvas->Clear(px, py + 1, 1, ph - 2, color); + pCanvas->Clear(px + pw - 1, py + 1, 1, ph - 2, color); +} diff --git a/build/tests/WirelessChecker/src/frame.h b/build/tests/WirelessChecker/src/frame.h new file mode 100644 index 00000000..2fec1121 --- /dev/null +++ b/build/tests/WirelessChecker/src/frame.h @@ -0,0 +1,72 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checher + File: frame.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef WIRELESS_CHECHER_FRAME_H_ +#define WIRELESS_CHECHER_FRAME_H_ + +#include +#include "util/util.h" +#include + +class CFrame +{ +public: + enum { + ITEM_TEST_WM, + ITEM_TEST_NWM, + ITEM_TEST_FATAL, + ITEM_TEST_RECOVERY, + ITEM_NUM + }; +private: + u8 m_itemIndex; + OSMessageQueue m_EntrMsgq; + OSMessage m_EntrMsg[1]; + BOOL m_isEnter; + + static const u8 m_itemNum = ITEM_NUM; + void incRound() + { + if (m_itemNum) + { + m_itemIndex = (u8)((m_itemIndex + 1)%m_itemNum); + } + } + void decRound() + { + if (m_itemNum) + { + m_itemIndex = (u8)((m_itemNum + m_itemIndex - 1)%m_itemNum); + } + } +public: + CFrame(); + CFrame(u8 item); + virtual ~CFrame(); + void InitDisp(); + void CursorDisp(int xpos, int ystart, util::PaletteColor color); + void HelpDisp(util::PaletteColor color); + virtual void ProcessButton(); + u8 GetItemIndex() + { + return m_itemIndex; + } + BOOL IsEnter(); + BOOL AutoEnter(); + void DrawBorder(util::CCanvas* pCanvas, int px, int py, int pw, int ph, util::PaletteColor color); +}; + +#endif // WIRELESS_CHECHER_TEST_NWM_H_ diff --git a/build/tests/WirelessChecker/src/main.cpp b/build/tests/WirelessChecker/src/main.cpp new file mode 100644 index 00000000..0069788b --- /dev/null +++ b/build/tests/WirelessChecker/src/main.cpp @@ -0,0 +1,135 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checker + File: main.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include +#include "util/util.h" +#include "util/canvas.h" +#include "frame.h" +#include "test_wm.h" +#include "test_nwm.h" +#include "test_fatal.h" +#include "test_recovery.h" +#include + +namespace +{ + +} +// end of anonymous namespace + + +void +TwlStartUp(void) +{ + +} + +void +TwlMain(void) +{ + BOOL isFatalChecking = FALSE; + util::Init(); + + OSDeliverArgInfo argInfo; + if (TRUE == OS_IsValidDeliverArg()) + { + OS_InitDeliverArgInfo(&argInfo, 0); + OS_DecodeDeliverArg(); + if( (OS_GetDeliverArgc() > 0) && ( STD_CompareNString( (const char *)OS_GetDeliverArgv(1), "fatal", 3 ) == 0 ) ) + { + isFatalChecking = TRUE; + } + } + + // display on + util::WaitVBlankIntr(); + util::dispOn(); + + CFrame menu(isFatalChecking == TRUE ? CFrame::ITEM_TEST_RECOVERY:CFrame::ITEM_TEST_WM); + if (isFatalChecking == TRUE) + { + menu.AutoEnter(); + } + CTestWm wm; + CTestNwm nwm; + CTestFatal fatal; + CTestRecovery rcv; + menu.InitDisp(); + + for (;;) + { + util::UpdateGamePad(); + menu.ProcessButton(); + menu.CursorDisp(16*1, 16*5, util::COLOR_LIMEGREEN); + menu.HelpDisp(util::COLOR_WHITE); + + if (menu.IsEnter()) + { + BOOL result; + u8 itemidx = menu.GetItemIndex(); + util::CCanvas* pcm = util::GetMain1Canvas(); + + switch (itemidx) + { + case CFrame::ITEM_TEST_WM: + pcm->Clear(16*12, 16*5, 16*3, 16, util::COLOR_BLACK); + pcm->Print(16*12, 16*5, util::COLOR_YELLOW, L"TESTING"); + util::WaitVBlankIntr(); + util::UpdateDisplay(); + result = wm.WirelessTest(); + pcm->Clear(16*12, 16*5, 16*3, 16, util::COLOR_BLACK); + pcm->Print(16*12, 16*5, result == TRUE ? util::COLOR_TURQUOISE:util::COLOR_RED, result == TRUE ? L"SUCCESS":L"FAILURE"); + break; + case CFrame::ITEM_TEST_NWM: + pcm->Clear(16*12, 16*6, 16*3, 16, util::COLOR_BLACK); + pcm->Print(16*12, 16*6, util::COLOR_YELLOW, L"TESTING"); + util::WaitVBlankIntr(); + util::UpdateDisplay(); + result = nwm.WirelessTest(); + pcm->Clear(16*12, 16*6, 16*3, 16, util::COLOR_BLACK); + pcm->Print(16*12, 16*6, result == TRUE ? util::COLOR_TURQUOISE:util::COLOR_RED, result == TRUE ? L"SUCCESS":L"FAILURE"); + break; + case CFrame::ITEM_TEST_FATAL: + pcm->Clear(16*12, 16*7, 16*3, 16, util::COLOR_BLACK); + pcm->Print(16*12, 16*7, util::COLOR_YELLOW, L"TESTING"); + result = fatal.WrackTest(); + pcm->Clear(16*12, 16*7, 16*3, 16, util::COLOR_BLACK); + pcm->Print(16*12, 16*7, result == TRUE ? util::COLOR_TURQUOISE:util::COLOR_RED, result == TRUE ? L"SUCCESS":L"FAILURE"); + break; + case CFrame::ITEM_TEST_RECOVERY: + pcm->Clear(16*12, 16*8, 16*3, 16, util::COLOR_BLACK); + pcm->Print(16*12, 16*8, util::COLOR_YELLOW, L"TESTING"); + if (isFatalChecking == FALSE) + { + result = rcv.RecoveryTest(); + } else { + result = rcv.RecoveryTest2(); + isFatalChecking = FALSE; + } + pcm->Clear(16*12, 16*8, 16*3, 16, util::COLOR_BLACK); + pcm->Print(16*12, 16*8, result == TRUE ? util::COLOR_TURQUOISE:util::COLOR_RED, result == TRUE ? L"SUCCESS":L"FAILURE"); + break; + } + } + + util::WaitVBlankIntr(); + util::UpdateDisplay(); + } + +} diff --git a/build/tests/WirelessChecker/src/test.cpp b/build/tests/WirelessChecker/src/test.cpp new file mode 100644 index 00000000..4dd480af --- /dev/null +++ b/build/tests/WirelessChecker/src/test.cpp @@ -0,0 +1,96 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checker + File: main.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include "util/canvas.h" +#include "util/util.h" +#include "util/wprintf.h" +#include +#include +#include +#include +//#include +#include +#include "test.h" + +CTest::CTest() : m_state(TEST_STATE_NONE) +{ + m_pc = util::GetSub1Canvas(); +} + +CTest::~CTest() +{ + +} + +BOOL +CTest::Init(void) +{ + return TRUE; +} + +BOOL +CTest::Enable(void) +{ + return TRUE; +} + +BOOL +CTest::ScanTest(void) +{ + return TRUE; +} + +BOOL +CTest::Disable(void) +{ + return TRUE; +} + +BOOL +CTest::End(void) +{ + return TRUE; +} + +u8 +CTest::GetState(void) +{ + return m_state; +} + +void CTest::LogClear(util::CCanvas* pc) +{ + pc->Clear(0, 0, 256, 16*9, util::COLOR_BLACK); + m_line = 0; + util::WaitVBlankIntr(); + util::UpdateDisplay(); +} + +void +CTest::LogPrintf(util::CCanvas* pc, const NNSG2dChar* text, ...) +{ + std::auto_ptr pLocalBuffer(new wchar_t[LOCAL_BUFFER_LEN]); + va_list args; + + va_start(args, text); + util::VSNWPrintf(pLocalBuffer.get(), LOCAL_BUFFER_LEN, text, args); + va_end(args); + pc->Print(16*1, 16*m_line++, util::COLOR_WHITE, pLocalBuffer.get()); + util::WaitVBlankIntr(); + util::UpdateDisplay(); +} diff --git a/build/tests/WirelessChecker/src/test.h b/build/tests/WirelessChecker/src/test.h new file mode 100644 index 00000000..21c4d985 --- /dev/null +++ b/build/tests/WirelessChecker/src/test.h @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checher + File: test.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef WIRELESS_CHECHER_TEST_H_ +#define WIRELESS_CHECHER_TEST_H_ + +#include +#include "util/util.h" +#include "util/canvas.h" +#include +#include +#include + +class CTest + +{ +private: + u8 m_line; + static const int LOCAL_BUFFER_LEN = 1024; +public: + enum { + TEST_STATE_NONE, + TEST_STATE_INITIALIZED, + TEST_STATE_ENABLED, + TEST_STATE_NUM + }; + u8 m_state; + util::CCanvas *m_pc; + CTest(); + virtual ~CTest(); + virtual BOOL Init(void); + virtual BOOL Enable(void); + virtual BOOL ScanTest(void); + virtual BOOL Disable(void); + virtual BOOL End(void); + u8 GetState(void); + void LogClear(util::CCanvas* pc); + void LogPrintf(util::CCanvas* pc, const NNSG2dChar* text, ...); +}; + +#endif // WIRELESS_CHECHER_TEST_H_ diff --git a/build/tests/WirelessChecker/src/test_fatal.cpp b/build/tests/WirelessChecker/src/test_fatal.cpp new file mode 100644 index 00000000..a3684aca --- /dev/null +++ b/build/tests/WirelessChecker/src/test_fatal.cpp @@ -0,0 +1,130 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checker + File: test_fatal.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "util/util.h" +#include "util/canvas.h" +#include "test_fatal.h" +#include "nwm_arm9_private.h" +#pragma exceptions on + +extern "C" { +extern NWMRetCode NWMi_WrackFirmware(NWMCallbackFunc callback); +} + +namespace +{ + OSMessageQueue m_AsyncMsgq; + OSMessage m_AsyncMsg[1]; + + void m_WrackFirmCallback(void *arg) + { + NWMCallback *cb = (NWMCallback*)arg; + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->retcode == NWM_RETCODE_FATAL_ERROR ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + + } + + void m_InitMessage(void) + { + OS_InitMessageQueue(&m_AsyncMsgq, m_AsyncMsg, sizeof(m_AsyncMsg)/sizeof(m_AsyncMsg[0])); + } + + BOOL m_WaitCallback(void) + { + OSMessage msg; + (void)OS_ReceiveMessage(&m_AsyncMsgq, &msg, OS_MESSAGE_BLOCK); + return (BOOL)msg; + } +} + + + + + +CTestFatal::CTestFatal() +{ + m_InitMessage(); +} + +CTestFatal::~CTestFatal() +{ + +} + +BOOL +CTestFatal::Wrack(void) +{ + try + { + if (m_state < TEST_STATE_INITIALIZED) + { + throw L"ステートが不正です.\n"; + } + + if (NWM_RETCODE_OPERATING != NWMi_WrackFirmware(m_WrackFirmCallback)) + { + throw L"WrackFirmware 失敗.\n"; + } + if (m_WaitCallback() == FALSE) + { + throw L"WrackFirmware 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"WrackFirmware 成功.\n"); + + } + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + return TRUE; +} + +BOOL +CTestFatal::WrackTest(void) +{ + try + { + if (FALSE == Init()) + { + throw L"Init() 失敗.\n"; + } + + if (FALSE == Wrack()) + { + End(); + throw L"Wrack() 失敗.\n"; + } + + if (FALSE == End()) + { + throw L"End() 失敗.\n"; + } + } + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + LogPrintf(m_pc, L"テストが完了しました.\n"); + + return TRUE; +} diff --git a/build/tests/WirelessChecker/src/test_fatal.h b/build/tests/WirelessChecker/src/test_fatal.h new file mode 100644 index 00000000..128d582d --- /dev/null +++ b/build/tests/WirelessChecker/src/test_fatal.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checher + File: test_fatal.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef WIRELESS_CHECHER_TEST_FATAL_H_ +#define WIRELESS_CHECHER_TEST_FATAL_H_ + +#include +#include "test.h" +#include "test_nwm.h" +#include "util/canvas.h" + +class CTestFatal + : public CTestNwm +{ +private: +public: + CTestFatal(); + virtual ~CTestFatal(); + BOOL Wrack(void); + BOOL WrackTest(void); +}; + + +#endif // WIRELESS_CHECHER_TEST_FATAL_H_ diff --git a/build/tests/WirelessChecker/src/test_nwm.cpp b/build/tests/WirelessChecker/src/test_nwm.cpp new file mode 100644 index 00000000..127afab7 --- /dev/null +++ b/build/tests/WirelessChecker/src/test_nwm.cpp @@ -0,0 +1,355 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checker + File: test_nwm.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "util/util.h" +#include "util/canvas.h" +#include "test_nwm.h" +#pragma exceptions on + +namespace test_nwm +{ + OSMessageQueue m_AsyncMsgq; + OSMessage m_AsyncMsg[1]; + void m_InitMessage(void); + + void m_LoadDeviceCallback(void *arg) + { + NWMCallback *cb = (NWMCallback*)arg; + + // TODO: get FW ver and RegDomain? + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->retcode == NWM_RETCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + } + + void m_OpenCallback(void *arg) + { + NWMCallback *cb = (NWMCallback*)arg; + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->retcode == NWM_RETCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + + } + + void m_UnloadDeviceCallback(void *arg) + { + NWMCallback *cb = (NWMCallback*)arg; + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->retcode == NWM_RETCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + } + + void m_CloseCallback(void *arg) + { + NWMCallback *cb = (NWMCallback*)arg; + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->retcode == NWM_RETCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + + } + + void m_ScanCallback(void *arg) + { + NWMStartScanCallback *cb = (NWMStartScanCallback*)arg; + + OS_TPrintf("Number of BSS: %d\n", cb->bssDescCount); + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->retcode == NWM_RETCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + + } + + void m_InitMessage(void) + { + OS_InitMessageQueue(&m_AsyncMsgq, m_AsyncMsg, sizeof(m_AsyncMsg)/sizeof(m_AsyncMsg[0])); + } + + BOOL m_WaitCallback(void) + { + OSMessage msg; + (void)OS_ReceiveMessage(&m_AsyncMsgq, &msg, OS_MESSAGE_BLOCK); + return (BOOL)msg; + } +} + + + + + +CTestNwm::CTestNwm() : m_pNwmBuffer(0), m_pScanBuffer(0) +{ + test_nwm::m_InitMessage(); +} + +CTestNwm::~CTestNwm() +{ + +} + + +BOOL +CTestNwm::Init(void) +{ + LogClear(m_pc); + + try + { + if (m_state != TEST_STATE_NONE) + { + throw L"ステートが不正です.\n"; + } + if (m_pNwmBuffer) + { + delete [] m_pNwmBuffer; + m_pNwmBuffer = 0; + throw L"NWMバッファが不正です.\n"; + } + + m_pNwmBuffer = new u8 [NWM_SYSTEM_BUF_SIZE + 0x20]; + + + if (NWM_RETCODE_SUCCESS != NWM_Init((void*)MATH_ROUNDUP((u32)m_pNwmBuffer, 32), NWM_SYSTEM_BUF_SIZE, m_DmaNo)) + { + throw L"NWM_Init 失敗.\n"; + } + + LogPrintf(m_pc, L"NWM_Init 成功.\n"); + } + + catch (const wchar_t* string) + { + delete [] m_pNwmBuffer; + m_pNwmBuffer = 0; + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + m_state = TEST_STATE_INITIALIZED; + + return TRUE; +} + +BOOL +CTestNwm::Enable(void) +{ + try { + if (m_state != TEST_STATE_INITIALIZED) + { + throw L"ステートが不正です.\n"; + } + + if (NWM_RETCODE_OPERATING != NWM_LoadDevice(test_nwm::m_LoadDeviceCallback)) + { + throw L"NWM_LoadDevice 失敗.\n"; + } + + if (test_nwm::m_WaitCallback() == FALSE) + { + throw L"NWM_LoadDevice 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"NWM_LoadDevice 成功.\n"); + + if (NWM_RETCODE_OPERATING != NWM_Open(test_nwm::m_OpenCallback)) + { + throw L"NWM_Open 失敗.\n"; + } + if (test_nwm::m_WaitCallback() == FALSE) + { + throw L"NWM_Open 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"NWM_Open 成功.\n"); + } + + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + m_state = TEST_STATE_ENABLED; + return TRUE; +} + +BOOL +CTestNwm::ScanTest(void) +{ + try + { + + if (m_state != TEST_STATE_ENABLED) + { + throw L"ステートが不正です.\n"; + } + + if (m_pScanBuffer) + { + throw L"Scanバッファが不正です.\n"; + } + + m_pScanBuffer = new u8 [NWM_SIZE_SCANBUF_MAX + 0x20]; + + NWMScanParam param; + + MI_CpuClear8(m_pScanBuffer, NWM_SIZE_SCANBUF_MAX + 0x20); + DC_StoreRange(m_pScanBuffer, NWM_SIZE_SCANBUF_MAX + 0x20); + param.scanBuf = (NWMBssDesc*)MATH_ROUNDUP((u32)m_pScanBuffer, 32); + param.scanBufSize = NWM_SIZE_SCANBUF_MAX; + param.channelList = (u16)(NWM_GetAllowedChannel() >> 1); + param.channelDwellTime = NWM_GetDispersionScanPeriod(NWM_SCANTYPE_ACTIVE); + param.scanType = NWM_SCANTYPE_ACTIVE; + param.ssidLength = 0; + MI_CpuFill8(param.ssid, 0xFF, sizeof(param.ssid)); + + if (NWM_RETCODE_OPERATING != NWM_StartScan(test_nwm::m_ScanCallback, ¶m)) + { + throw L"NWM_StartScan 失敗.\n"; + } + + if (test_nwm::m_WaitCallback() == FALSE) + { + throw L"NWM_StartScan 非同期処理失敗.\n"; + } + + LogPrintf(m_pc, L"NWM_StartScan 成功.\n"); + + } + + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + delete [] m_pScanBuffer; + m_pScanBuffer = 0; + + return TRUE; +} + +BOOL +CTestNwm::Disable(void) +{ + try { + if (m_state != TEST_STATE_ENABLED) + { + throw L"ステートが不正です.\n"; + } + + if (NWM_RETCODE_OPERATING != NWM_Close(test_nwm::m_CloseCallback)) + { + throw L"NWM_Close 失敗.\n"; + } + if (test_nwm::m_WaitCallback() == FALSE) + { + throw L"NWM_Close 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"NWM_Close 成功.\n"); + + if (NWM_RETCODE_OPERATING != NWM_UnloadDevice(test_nwm::m_UnloadDeviceCallback)) + { + throw L"NWM_UnloadDevice 失敗.\n"; + } + if (test_nwm::m_WaitCallback() == FALSE) + { + throw L"NWM_UnloadDevice 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"NWM_UnloadDevice 成功.\n"); + } + + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + m_state = TEST_STATE_INITIALIZED; + return TRUE; + +} + +BOOL +CTestNwm::End(void) +{ + try + { + if (m_state != TEST_STATE_INITIALIZED) + { + throw L"ステートが不正です.\n"; + } + if (NWM_RETCODE_SUCCESS != NWM_End()) + { + throw L"NWM_End 失敗.\n"; + } + + LogPrintf(m_pc, L"NWM_End 成功.\n"); + } + + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + m_state = TEST_STATE_NONE; + delete [] m_pNwmBuffer; + m_pNwmBuffer = 0; + + return TRUE; +} + +BOOL +CTestNwm::WirelessTest(void) +{ + try + { + if (FALSE == Init()) + { + throw L"Init() 失敗.\n"; + } + if (FALSE == Enable()) + { + End(); + throw L"Enable() 失敗.\n"; + } + if (FALSE == ScanTest()) + { + Disable(); + End(); + throw L"ScanTest() 失敗.\n"; + } + if (FALSE == Disable()) + { + throw L"Disable() 失敗.\n"; + } + if (FALSE == End()) + { + throw L"End() 失敗.\n"; + } + } + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + LogPrintf(m_pc, L"テストが完了しました.\n"); + + return TRUE; +} diff --git a/build/tests/WirelessChecker/src/test_nwm.h b/build/tests/WirelessChecker/src/test_nwm.h new file mode 100644 index 00000000..cbc725f6 --- /dev/null +++ b/build/tests/WirelessChecker/src/test_nwm.h @@ -0,0 +1,52 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checher + File: test_nwm.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef WIRELESS_CHECHER_TEST_NWM_H_ +#define WIRELESS_CHECHER_TEST_NWM_H_ + +#include +#include "test.h" + +namespace test_nwm +{ + void m_LoadDeviceCallback(void *arg); + void m_OpenCallback(void *arg); + void m_UnloadDeviceCallback(void *arg); + void m_CloseCallback(void *arg); + void m_ScanCallback(void *arg); + BOOL m_WaitCallback(void); +} + +class CTestNwm + : public CTest +{ +private: + static const u8 m_DmaNo = 3; + u8 *m_pNwmBuffer; + u8 *m_pScanBuffer; +public: + CTestNwm(); + virtual ~CTestNwm(); + BOOL Init(void); + BOOL Enable(void); + BOOL ScanTest(void); + BOOL Disable(void); + BOOL End(void); + BOOL WirelessTest(void); +}; + + +#endif // WIRELESS_CHECHER_TEST_NWM_H_ diff --git a/build/tests/WirelessChecker/src/test_recovery.cpp b/build/tests/WirelessChecker/src/test_recovery.cpp new file mode 100644 index 00000000..ab8ae1f0 --- /dev/null +++ b/build/tests/WirelessChecker/src/test_recovery.cpp @@ -0,0 +1,97 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checker + File: test_recovery.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "util/util.h" +#include "util/canvas.h" +#include "test_recovery.h" +#include "nwm_arm9_private.h" +#pragma exceptions on + + +CTestRecovery::CTestRecovery() +{ +} + +CTestRecovery::~CTestRecovery() +{ + +} + + +BOOL +CTestRecovery::RecoveryTest(void) +{ + try + { + if (FALSE == Init()) + { + throw L"Init() 失敗.\n"; + } + + if (FALSE == Enable()) + { + End(); + throw L"Enable() 失敗.\n"; + } + + if (FALSE == Wrack()) + { + Disable(); + End(); + throw L"Wrack() 失敗.\n"; + } + + LogPrintf(m_pc, L"FATALエラーを待っています.\n"); + + if (TRUE == test_nwm::m_WaitCallback()) + { + Disable(); + End(); + throw L"FATALエラーが起こりませんでした.\n"; + } + + LogPrintf(m_pc, L"FATALエラーが発生しました.\n"); + } + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + m_state = TEST_STATE_INITIALIZED; + End(); + LogPrintf(m_pc, L"3秒後にHWリセットを行います.\n"); + OS_Sleep(3000); + + OSDeliverArgInfo argInfo; + OS_InitDeliverArgInfo(&argInfo, 0); + OSi_SetDeliverArgState( OS_DELIVER_ARG_BUF_ACCESSIBLE | OS_DELIVER_ARG_BUF_WRITABLE ); + OS_SetStringToDeliverArg( "fatal" ); + OS_EncodeDeliverArg(); + OS_DoApplicationJump( + *(const OSTitleId*)(HW_TWL_ROM_HEADER_BUF + 0x230), + OS_APP_JUMP_NORMAL); + + return TRUE; +} + +BOOL +CTestRecovery::RecoveryTest2(void) +{ + return WirelessTest(); +} + diff --git a/build/tests/WirelessChecker/src/test_recovery.h b/build/tests/WirelessChecker/src/test_recovery.h new file mode 100644 index 00000000..c346bc17 --- /dev/null +++ b/build/tests/WirelessChecker/src/test_recovery.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checher + File: test_recovery.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef WIRELESS_CHECHER_TEST_RECOVERY_H_ +#define WIRELESS_CHECHER_TEST_RECOVERY_H_ + +#include +#include "test.h" +#include "test_fatal.h" +#include "util/canvas.h" + +class CTestRecovery + : public CTestFatal +{ +private: +public: + CTestRecovery(); + ~CTestRecovery(); + BOOL RecoveryTest(void); + BOOL RecoveryTest2(void); +}; + + +#endif // WIRELESS_CHECHER_TEST_RECOVERY_H_ diff --git a/build/tests/WirelessChecker/src/test_wm.cpp b/build/tests/WirelessChecker/src/test_wm.cpp new file mode 100644 index 00000000..f2b2a151 --- /dev/null +++ b/build/tests/WirelessChecker/src/test_wm.cpp @@ -0,0 +1,376 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checker + File: test_nwm.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "util/util.h" +#include "util/canvas.h" +#include "test_wm.h" +#pragma exceptions on + +namespace +{ + OSMessageQueue m_AsyncMsgq; + OSMessage m_AsyncMsg[1]; + + void m_EnableCallback(void *arg) + { + WMCallback *cb = (WMCallback*)arg; + + // TODO: get FW ver and RegDomain? + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->errcode == WM_ERRCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + } + + void m_PowerOnCallback(void *arg) + { + WMCallback *cb = (WMCallback*)arg; + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->errcode == WM_ERRCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + + } + + void m_DisableCallback(void *arg) + { + WMCallback *cb = (WMCallback*)arg; + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->errcode == WM_ERRCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + } + + void m_PowerOffCallback(void *arg) + { + WMCallback *cb = (WMCallback*)arg; + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->errcode == WM_ERRCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + + } + + void m_ScanCallback(void *arg) + { + WMStartScanExCallback *cb = (WMStartScanExCallback*)arg; + + OS_TPrintf("Number of BSS: %d\n", cb->bssDescCount); + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->errcode == WM_ERRCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + + } + + void m_EndScanCallback(void *arg) + { + WMCallback *cb = (WMCallback*)arg; + + if (FALSE == OS_SendMessage(&m_AsyncMsgq, (OSMessage)(cb->errcode == WM_ERRCODE_SUCCESS ? TRUE:FALSE), OS_MESSAGE_NOBLOCK)) + { + } + + } + + void m_InitMessage(void) + { + OS_InitMessageQueue(&m_AsyncMsgq, m_AsyncMsg, sizeof(m_AsyncMsg)/sizeof(m_AsyncMsg[0])); + } + + BOOL m_WaitCallback(void) + { + OSMessage msg; + (void)OS_ReceiveMessage(&m_AsyncMsgq, &msg, OS_MESSAGE_BLOCK); + return (BOOL)msg; + } +} + + + + + +CTestWm::CTestWm() : m_pWmBuffer(0), m_pScanBuffer(0) +{ + m_InitMessage(); + m_pc = util::GetSub1Canvas(); +} + +CTestWm::~CTestWm() +{ + +} + + +BOOL +CTestWm::Init(void) +{ + LogClear(m_pc); + + try + { + if (m_state != TEST_STATE_NONE) + { + throw L"ステートが不正です.\n"; + } + if (m_pWmBuffer) + { + delete [] m_pWmBuffer; + m_pWmBuffer = 0; + throw L"WM用バッファが不正です.\n"; + } + + m_pWmBuffer = new u8 [WM_SYSTEM_BUF_SIZE + 0x20]; + + + if (WM_ERRCODE_SUCCESS != WM_Init((void*)MATH_ROUNDUP((u32)m_pWmBuffer, 32), m_DmaNo)) + { + throw L"WM_Init 失敗.\n"; + } + + LogPrintf(m_pc, L"WM_Init 成功.\n"); + + } + + catch (const wchar_t* string) + { + delete [] m_pWmBuffer; + m_pWmBuffer = 0; + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + m_state = TEST_STATE_INITIALIZED; + + return TRUE; +} + +BOOL +CTestWm::Enable(void) +{ + try { + + if (m_state != TEST_STATE_INITIALIZED) + { + throw L"ステートが不正です.\n"; + } + + if (WM_ERRCODE_OPERATING != WM_Enable(m_EnableCallback)) + { + throw L"WM_Enable 失敗.\n"; + } + if (m_WaitCallback() == FALSE) + { + throw L"WM_Enable 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"WM_Enable 成功.\n"); + if (WM_ERRCODE_OPERATING != WM_PowerOn(m_PowerOnCallback)) + { + throw L"WM_PowerOn 失敗.\n"; + } + if (m_WaitCallback() == FALSE) + { + throw L"WM_PowerOn 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"WM_PowerOn 成功.\n"); + } + + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + m_state = TEST_STATE_ENABLED; + return TRUE; +} + +BOOL +CTestWm::ScanTest(void) +{ + try + { + + if (m_state != TEST_STATE_ENABLED) + { + throw L"ステートが不正です.\n"; + } + + if (m_pScanBuffer) + { + throw L"Scanバッファが不正です.\n"; + } + + m_pScanBuffer = new u8 [WM_SIZE_SCAN_EX_BUF + 0x20]; + + WMScanExParam param; + + MI_CpuClear8(m_pScanBuffer, WM_SIZE_SCAN_EX_BUF + 0x20); + DC_StoreRange(m_pScanBuffer, WM_SIZE_SCAN_EX_BUF + 0x20); + param.scanBuf = (WMBssDesc*)MATH_ROUNDUP((u32)m_pScanBuffer, 32); + param.scanBufSize = WM_SIZE_SCAN_EX_BUF; + param.channelList = (u16)WM_GetAllowedChannel(); + param.maxChannelTime = WM_GetDispersionScanPeriod(); + param.scanType = WM_SCANTYPE_ACTIVE; + param.ssidLength = 0; + MI_CpuFill8(param.ssid, 0xFF, sizeof(param.ssid)); + param.ssidMatchLength = 0; + + if (WM_ERRCODE_OPERATING != WM_StartScanEx(m_ScanCallback, ¶m)) + { + throw L"WM_StartScanEx 失敗.\n"; + } + + if (m_WaitCallback() == FALSE) + { + throw L"WM_StartScanEx 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"WM_StartScanEx 成功.\n"); + + if (WM_ERRCODE_OPERATING != WM_EndScan(m_EndScanCallback)) + { + throw L"WM_EndScan 失敗.\n"; + } + + if (m_WaitCallback() == FALSE) + { + throw L"WM_EndScan 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"WM_EndScan 成功.\n"); + + } + + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + delete [] m_pScanBuffer; + m_pScanBuffer = 0; + + return TRUE; +} + +BOOL +CTestWm::Disable(void) +{ + try { + if (m_state != TEST_STATE_ENABLED) + { + throw L"ステートが不正です.\n"; + } + + if (WM_ERRCODE_OPERATING != WM_PowerOff(m_PowerOffCallback)) + { + throw L"WM_PowerOff 失敗.\n"; + } + if (m_WaitCallback() == FALSE) + { + throw L"WM_PowerOff 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"WM_PowerOff 成功.\n"); + + if (WM_ERRCODE_OPERATING != WM_Disable(m_DisableCallback)) + { + throw L"WM_Disable 失敗.\n"; + } + if (m_WaitCallback() == FALSE) + { + throw L"WM_Disable 非同期処理失敗.\n"; + } + LogPrintf(m_pc, L"WM_Disable 成功.\n"); + } + + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + m_state = TEST_STATE_INITIALIZED; + return TRUE; + +} + +BOOL +CTestWm::End(void) +{ + try + { + if (m_state != TEST_STATE_INITIALIZED) + { + throw L"ステートが不正です\n"; + } + if (WM_ERRCODE_SUCCESS != WM_Finish()) + { + throw L"WM_Finish 失敗.\n"; + } + LogPrintf(m_pc, L"WM_Finish 成功.\n"); + } + + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + m_state = TEST_STATE_NONE; + delete [] m_pWmBuffer; + m_pWmBuffer = 0; + + return TRUE; +} + +BOOL +CTestWm::WirelessTest(void) +{ + try + { + if (FALSE == Init()) + { + throw L"Init() 失敗.\n"; + } + if (FALSE == Enable()) + { + End(); + throw L"Enable() 失敗.\n"; + } + if (FALSE == ScanTest()) + { + Disable(); + End(); + throw L"ScanTest() 失敗.\n"; + } + if (FALSE == Disable()) + { + throw L"Disable() 失敗.\n"; + } + if (FALSE == End()) + { + throw L"End() 失敗.\n"; + } + } + catch (const wchar_t* string) + { + LogPrintf(m_pc, L"%s", string); + return FALSE; + } + + LogPrintf(m_pc, L"テストが完了しました.\n"); + + return TRUE; +} diff --git a/build/tests/WirelessChecker/src/test_wm.h b/build/tests/WirelessChecker/src/test_wm.h new file mode 100644 index 00000000..958a4919 --- /dev/null +++ b/build/tests/WirelessChecker/src/test_wm.h @@ -0,0 +1,43 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checher + File: test_wm.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef WIRELESS_CHECHER_TEST_WM_H_ +#define WIRELESS_CHECHER_TEST_WM_H_ + +#include +#include "test.h" +#include "util/canvas.h" + +class CTestWm + : public CTest +{ +private: + static const u8 m_DmaNo = 3; + u8 *m_pWmBuffer; + u8 *m_pScanBuffer; +public: + CTestWm(); + virtual ~CTestWm(); + BOOL Init(void); + BOOL Enable(void); + BOOL ScanTest(void); + BOOL Disable(void); + BOOL End(void); + BOOL WirelessTest(void); +}; + + +#endif // WIRELESS_CHECHER_TEST_WM_H_ diff --git a/build/tests/WirelessChecker/src/util/canvas.cpp b/build/tests/WirelessChecker/src/util/canvas.cpp new file mode 100644 index 00000000..9e9156ef --- /dev/null +++ b/build/tests/WirelessChecker/src/util/canvas.cpp @@ -0,0 +1,175 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Nmenu + File: Canvas.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include "util/canvas.h" +#include "util/util.h" +#include "util/wprintf.h" +#include +#include +#include +#include +//#include +#include + +namespace util +{ + +CCanvas::CCanvas() +: m_pFont(NULL) +{ +} + +CCanvas::~CCanvas() +{ +} + +void +CCanvas::Init(NNS_GFD_DST_TYPE type, u32 offset, void* pScrBase, const NNSG2dFont* pFont) +{ + m_transType = type; + m_transOffset = offset; + m_pFont = pFont; + + NNS_G2dCharCanvasInitForBG( + &m_cc, + m_offscreen, + CANVAS_WIDTH, + CANVAS_HEIGHT, + NNS_G2D_CHARA_COLORMODE_16 ); + + NNS_G2dTextCanvasInit( + &m_txn, + &m_cc, + m_pFont, + TEXT_HSPACE, + TEXT_VSPACE ); + + NNS_G2dMapScrToCharText( + pScrBase, + CANVAS_WIDTH, + CANVAS_HEIGHT, + CANVAS_LEFT, + CANVAS_TOP, + NNS_G2D_TEXT_BG_WIDTH_256, + CANVAS_CHARACTER_OFFSET, + DEFAULT_COLOR_PALETTE ); +} + +void +CCanvas::Clear(PaletteColor c) +{ + NNS_G2dCharCanvasClear(&m_cc, c); + RegisterTransferTask(); +} + +void +CCanvas::Clear(int x, int y, int w, int h, PaletteColor c) +{ + const int px = MATH_CLAMP(x, 0, HW_LCD_WIDTH); + const int py = MATH_CLAMP(y, 0, HW_LCD_HEIGHT); + const int pw = MATH_CLAMP(x + w, px, HW_LCD_WIDTH) - px; + const int ph = MATH_CLAMP(y + h, py, HW_LCD_HEIGHT) - py; + + if( pw > 0 && ph > 0 ) + { + NNS_G2dCharCanvasClearArea(&m_cc, c, px, py, pw, ph); + RegisterTransferTask(); + } +} + +void +CCanvas::Print(int x, int y, PaletteColor c, const NNSG2dChar* text) +{ + NNS_G2dTextCanvasDrawText( + &m_txn, + x, + y, + c, + DRAWTEXT_FLAG_DEFAULT, + text ); + + RegisterTransferTask(); +} + +void +CCanvas::Printf(int x, int y, PaletteColor c, const NNSG2dChar* text, ...) +{ + std::auto_ptr pLocalBuffer(new wchar_t[LOCAL_BUFFER_LEN]); + va_list args; + + va_start(args, text); + VSNWPrintf(pLocalBuffer.get(), LOCAL_BUFFER_LEN, text, args); + va_end(args); + + Print(x, y, c, pLocalBuffer.get()); +} + + +void +CCanvas::RegisterTransferTask() +{ + if( ! m_bTransferRegsitered ) + { + NNS_GfdRegisterNewVramTransferTask( + m_transType, + m_transOffset, + m_offscreen, + sizeof(m_offscreen) ); + + m_bTransferRegsitered = true; + } +} + +void +CCanvas::ResetTransferTask() +{ + m_bTransferRegsitered = false; +} + + +std::wstring +CCanvas::WrapText(std::wstring text, int width) +{ + int textWidth = 0; + + for( u32 i = 0; i < text.length(); ++i ) + { + const int charWidth = NNS_G2dFontGetCharWidth(m_pFont, text[i]); + + if( text[i] == L'\n' ) + { + textWidth = 0; + } + else if( (textWidth > 0) && ((textWidth + charWidth) > width) ) + { + text.insert(i - 1, 1, L'\n'); + textWidth = 0; + } + else + { + textWidth += charWidth + TEXT_HSPACE; + } + } + + return text; +} + + + +} +// end of namespace tlib diff --git a/build/tests/WirelessChecker/src/util/canvas.h b/build/tests/WirelessChecker/src/util/canvas.h new file mode 100644 index 00000000..0e6c7781 --- /dev/null +++ b/build/tests/WirelessChecker/src/util/canvas.h @@ -0,0 +1,78 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Nmenu + File: Canvas.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef TLIB_CONTROL_CANVAS_H_ +#define TLIB_CONTROL_CANVAS_H_ + +#define NNS_G2D_UNICODE +#include +#include +#include +#include +#include "util.h" + +namespace util +{ + +class CCanvas +{ +private: + static const int CANVAS_WIDTH = 32; + static const int CANVAS_HEIGHT = 24; + static const int CANVAS_LEFT = 0; + static const int CANVAS_TOP = 0; + static const int TEXT_HSPACE = 1; + static const int TEXT_VSPACE = 1; + static const int CANVAS_CHARACTER_OFFSET = 1; + + static const int LOCAL_BUFFER_LEN = 1024; + + static const u32 DRAWTEXT_FLAG_DEFAULT = ( NNS_G2D_VERTICALORIGIN_TOP + | NNS_G2D_HORIZONTALORIGIN_LEFT + | NNS_G2D_HORIZONTALALIGN_LEFT ); + +private: + NNSG2dCharCanvas m_cc; + NNSG2dTextCanvas m_txn; + GXCharFmt16 m_offscreen[32 * 24]; + const NNSG2dFont* m_pFont; + NNS_GFD_DST_TYPE m_transType; + u32 m_transOffset; + bool m_bTransferRegsitered; + +public: + CCanvas(); + ~CCanvas(); + +public: + void Init(NNS_GFD_DST_TYPE type, u32 offset, void* pScrBase, const NNSG2dFont* pFont); + void Clear (PaletteColor c); + void Clear (int x, int y, int w, int h, PaletteColor c); + void Print (int x, int y, PaletteColor c, const NNSG2dChar* text); + void Printf(int x, int y, PaletteColor c, const NNSG2dChar* text, ...); + std::wstring WrapText(std::wstring text, int width); + + void ResetTransferTask(); + +protected: + void RegisterTransferTask(); +}; + +} +// end of namespace tlib + + +#endif // TLIB_CONTROL_CANVAS_H_ diff --git a/build/tests/WirelessChecker/src/util/memory.cpp b/build/tests/WirelessChecker/src/util/memory.cpp new file mode 100644 index 00000000..5e0d1d57 --- /dev/null +++ b/build/tests/WirelessChecker/src/util/memory.cpp @@ -0,0 +1,122 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Nmenu + File: Memory.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "util/memory.h" + + +namespace util +{ + + +namespace +{ + NNSFndHeapHandle shHeap; + NNSFndAllocator sAllocator; + OSMutex sLock; +} + + +void +InitMemory() +{ + u32 arenaLow = MATH_ROUNDUP ((u32)OS_GetMainArenaLo(), 16); + u32 arenaHigh = MATH_ROUNDDOWN((u32)OS_GetMainArenaHi(), 16); + u32 heapSize = arenaHigh - arenaLow; + void* heapMemory = OS_AllocFromMainArenaLo(heapSize, 16); + + shHeap = NNS_FndCreateExpHeap(heapMemory, heapSize); + SDK_ASSERT( shHeap != NNS_FND_HEAP_INVALID_HANDLE ); + + NNS_FndInitAllocatorForExpHeap(&sAllocator, shHeap, 4); + + OS_InitMutex(&sLock); +} + +NNSFndHeapHandle +GetHeapHandle() +{ + return shHeap; +} + +NNSFndAllocator* +GetAllocator() +{ + return &sAllocator; +} + +void* +Alloc(size_t size, int align) +{ + OS_LockMutex(&sLock); + SDK_ASSERT(NNS_FndCheckExpHeap(shHeap, NNS_FND_HEAP_ERROR_PRINT)); + void* p = NNS_FndAllocFromExpHeapEx(shHeap, size, align); + OS_UnlockMutex(&sLock); + + return p; +} + +void +Free(void* ptr) +{ + OS_LockMutex(&sLock); + SDK_ASSERT(NNS_FndCheckExpHeap(shHeap, NNS_FND_HEAP_ERROR_PRINT)); + SDK_ASSERT(NNS_FndCheckForMBlockExpHeap(ptr, shHeap, NNS_FND_HEAP_ERROR_PRINT)); + NNS_FndFreeToExpHeap(shHeap, ptr); + OS_UnlockMutex(&sLock); +} + + +} +// end of namespace util + + + + +//------------ global namespace ------------------------------------ + +void* +operator new(size_t size) +{ + // operator new[] で 32 byte アライメントを保証できないので + // operator new でも 32 byte アライメントは行わない。 + return util::Alloc(size, 4); +} + +void* +operator new[](size_t size) +{ + // operator new[] では 32 byteアライメントを保証できない。 + return util::Alloc(size, 4); +} + +void +operator delete(void* ptr) +{ + if( ptr != NULL ) + { + util::Free(ptr); + } +} + +void +operator delete[](void* ptr) +{ + if( ptr != NULL ) + { + util::Free(ptr); + } +} diff --git a/build/tests/WirelessChecker/src/util/memory.h b/build/tests/WirelessChecker/src/util/memory.h new file mode 100644 index 00000000..c0e1ed39 --- /dev/null +++ b/build/tests/WirelessChecker/src/util/memory.h @@ -0,0 +1,38 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Nmenu + File: Memory.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef TLIB_SYSTEM_MEMORY_H_ +#define TLIB_SYSTEM_MEMORY_H_ + +#include +#include + +namespace util +{ + +void InitMemory(); + +NNSFndAllocator* GetAllocator(); +NNSFndHeapHandle GetHeapHandle(); +void* Alloc(size_t size, int align=32); +void Free(void* ptr); + +} +// end of namespace tlib + + + +#endif // TLIB_SYSTEM_MEMORY_H_ diff --git a/build/tests/WirelessChecker/src/util/util.cpp b/build/tests/WirelessChecker/src/util/util.cpp new file mode 100644 index 00000000..5828b7e8 --- /dev/null +++ b/build/tests/WirelessChecker/src/util/util.cpp @@ -0,0 +1,276 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checker + File: util.cpp + + Copyright 2008 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "util/util.h" +#include "util/canvas.h" +#include "util/memory.h" +#include +#include + +extern u8 font_NFTR_begin[]; +extern u8 font_NFTR_end[]; + +namespace util +{ + GamePad System_GamePadState; + int System_BaseWidth; + int System_LineHeight; + + namespace + { + const int REPEAT_START_FRAME = 15; + const int REPEAT_INTERVAL = 30; + const u32 TASK_ARRAY_NUM = 4; + const int CANVAS_CHARACTER_OFFSET = 1; + + GXRgb COLOR_PALETTE[18] = + { + GX_RGB(26, 26, 26), + GX_RGB(31, 31, 31), + GX_RGB( 0, 0, 0), + + GX_RGB(31, 0, 3), + GX_RGB(30, 28, 0), + GX_RGB(21, 31, 0), + GX_RGB( 6, 23, 30), + GX_RGB( 0, 11, 30), + GX_RGB(25, 23, 1), + GX_RGB(22, 22, 22), + GX_RGB(16, 16, 16), + + GX_RGB(29, 31, 31) + }; + NNSG2dFont sFont; + CCanvas sCanvasMain1; + CCanvas sCanvasMain3; + CCanvas sCanvasSub1; + CCanvas sCanvasSub3; + + NNSGfdVramTransferTask sTaskArray[TASK_ARRAY_NUM]; + + void ClearVram( void ) + { + //--------------------------------------------------------------------------- + // All VRAM banks to LCDC + //--------------------------------------------------------------------------- + GX_SetBankForLCDC(GX_VRAM_LCDC_ALL); + + //--------------------------------------------------------------------------- + // Clear all LCDC space + //--------------------------------------------------------------------------- + MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE); + + //--------------------------------------------------------------------------- + // Disable the banks on LCDC + //--------------------------------------------------------------------------- + (void)GX_DisableBankForLCDC(); + + MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE); // clear OAM + MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE); // clear the standard palette + + MI_CpuFillFast((void*)HW_DB_OAM, 192, HW_DB_OAM_SIZE); // clear OAM + MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE); // clear the standard palette + } + + void InitFont(void* pNFTR) + { + NNS_G2dFontInitUTF16(&sFont, pNFTR); + + System_BaseWidth = NNS_G2dFontGetCellWidth(&sFont) / 2; + System_LineHeight = NNS_G2dFontGetLineFeed(&sFont); + } + + void VBlankIntr(void) + { + OS_SetIrqCheckFlag( OS_IE_V_BLANK ); + } + + + } // namespace + + void WaitVBlankIntr(void) + { + SVC_WaitVBlankIntr(); + } + + void dispOn(void) + { + GX_DispOn(); + GXS_DispOn(); + } + + CCanvas* GetMain1Canvas() { return &sCanvasMain1; } + CCanvas* GetMain3Canvas() { return &sCanvasMain3; } + CCanvas* GetSub1Canvas() { return &sCanvasSub1; } + CCanvas* GetSub3Canvas() { return &sCanvasSub3; } + + void UpdateGamePad(void) + { + u16 status = PAD_Read(); + + System_GamePadState.repeatTrigger = false; + + if( status != 0 ) + { + if( System_GamePadState.button == 0 ) + { + System_GamePadState.beginPress = 0; + } + else + { + System_GamePadState.beginPress++; + const int lapse = System_GamePadState.beginPress - REPEAT_START_FRAME; + + if( lapse >= 0 ) + { + if( (lapse % REPEAT_INTERVAL) == 0 ) + { + System_GamePadState.repeatTrigger = true; + } + } + } + } + + System_GamePadState.trigger = (u16)(status & (status ^ System_GamePadState.button)); + System_GamePadState.release = (u16)(System_GamePadState.button & (status ^ System_GamePadState.button)); + System_GamePadState.button = status; + } + + void UpdateDisplay(void) + { + sCanvasMain1.ResetTransferTask(); + sCanvasMain3.ResetTransferTask(); + sCanvasSub1 .ResetTransferTask(); + sCanvasSub3 .ResetTransferTask(); + NNS_GfdDoVramTransfer(); + } + + void Init() + { + OS_Init(); + FX_Init(); + GX_Init(); + + OS_InitTick(); + OS_InitAlarm(); + + GX_DispOff(); + GXS_DispOff(); + + RTC_Init(); + + OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr); + (void)OS_EnableIrqMask(OS_IE_V_BLANK); + (void)GX_VBlankIntr(TRUE); + (void)OS_EnableIrq(); + (void)OS_EnableInterrupts(); + + ClearVram(); + + InitMemory(); + + // assign vram banks + GX_SetBankForBG(GX_VRAM_BG_128_A); + GX_SetBankForOBJ(GX_VRAM_OBJ_16_F); + GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C); + GX_SetBankForSubOBJ(GX_VRAM_SUB_OBJ_16_I); + GX_SetBankForLCDC(GX_VRAM_LCDC_B); + + // init screen + // BG 1 を設定 + G2_SetBG1Control( + GX_BG_SCRSIZE_TEXT_256x256, // スクリーンサイズ 256x256 + GX_BG_COLORMODE_16, // カラーモード 16色 + GX_BG_SCRBASE_0x0000, // スクリーンベース + GX_BG_CHARBASE_0x04000, // キャラクタベース + GX_BG_EXTPLTT_01 ); // 拡張パレットスロット + + G2S_SetBG1Control( + GX_BG_SCRSIZE_TEXT_256x256, // スクリーンサイズ 256x256 + GX_BG_COLORMODE_16, // カラーモード 16色 + GX_BG_SCRBASE_0x0000, // スクリーンベース + GX_BG_CHARBASE_0x04000, // キャラクタベース + GX_BG_EXTPLTT_01 ); // 拡張パレットスロット + + // BG 2 を設定 + G2_SetBG2ControlText( + GX_BG_SCRSIZE_TEXT_256x256, // スクリーンサイズ 256x256 + GX_BG_COLORMODE_16, // カラーモード 16色 + GX_BG_SCRBASE_0x0800, // スクリーンベース + GX_BG_CHARBASE_0x0c000 ); // キャラクタベース + + G2S_SetBG2ControlText( + GX_BG_SCRSIZE_TEXT_256x256, // スクリーンサイズ 256x256 + GX_BG_COLORMODE_16, // カラーモード 16色 + GX_BG_SCRBASE_0x0800, // スクリーンベース + GX_BG_CHARBASE_0x0c000 ); // キャラクタベース + + // BG 3 を設定 + G2_SetBG3ControlText( + GX_BG_SCRSIZE_TEXT_256x256, // スクリーンサイズ 256x256 + GX_BG_COLORMODE_16, // カラーモード 16色 + GX_BG_SCRBASE_0x1000, // スクリーンベース + GX_BG_CHARBASE_0x14000 ); // キャラクタベース + + G2S_SetBG3ControlText( + GX_BG_SCRSIZE_TEXT_256x256, // スクリーンサイズ 256x256 + GX_BG_COLORMODE_16, // カラーモード 16色 + GX_BG_SCRBASE_0x1000, // スクリーンベース + GX_BG_CHARBASE_0x14000 ); // キャラクタベース + + // BG1/3 を可視に + GX_SetVisiblePlane ( GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3 ); + GXS_SetVisiblePlane( GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3 ); + + // BG1/2/3 の優先順位設定 + G2_SetBG1Priority(3); + G2_SetBG2Priority(2); + G2_SetBG3Priority(1); + G2S_SetBG1Priority(3); + G2S_SetBG2Priority(2); + G2S_SetBG3Priority(1); + + GX_LoadBGPltt(COLOR_PALETTE, 0, sizeof(COLOR_PALETTE)); + GXS_LoadBGPltt(COLOR_PALETTE, 0, sizeof(COLOR_PALETTE)); + + GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D); + GXS_SetGraphicsMode(GX_BGMODE_0); + GX_SetBGScrOffset(GX_BGSCROFFSET_0x00000); + GX_SetBGCharOffset(GX_BGCHAROFFSET_0x00000); + + InitFont(font_NFTR_begin); + + { + const u32 chrOffset = CANVAS_CHARACTER_OFFSET * sizeof(GXCharFmt16); + sCanvasMain1.Init(NNS_GFD_DST_2D_BG1_CHAR_MAIN, chrOffset, G2_GetBG1ScrPtr(), &sFont); + sCanvasMain3.Init(NNS_GFD_DST_2D_BG3_CHAR_MAIN, chrOffset, G2_GetBG3ScrPtr(), &sFont); + sCanvasSub1 .Init(NNS_GFD_DST_2D_BG1_CHAR_SUB, chrOffset, G2S_GetBG1ScrPtr(), &sFont); + sCanvasSub3 .Init(NNS_GFD_DST_2D_BG3_CHAR_SUB, chrOffset, G2S_GetBG3ScrPtr(), &sFont); + + NNS_GfdInitVramTransferManager(sTaskArray, TASK_ARRAY_NUM); + } + + PAD_Read(); + } + + u16 GetPadTrigger() + { + return static_cast(System_GamePadState.button); + } + +} // namespace util + diff --git a/build/tests/WirelessChecker/src/util/util.h b/build/tests/WirelessChecker/src/util/util.h new file mode 100644 index 00000000..a84e4afb --- /dev/null +++ b/build/tests/WirelessChecker/src/util/util.h @@ -0,0 +1,103 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Wireless Checher + File: util.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef WIRELESS_CHECHER_UTIL_H_ +#define WIRELESS_CHECHER_UTIL_H_ + +#include + +namespace util +{ + +const int DEFAULT_COLOR_PALETTE = 0; + +enum PaletteColor +{ + COLOR_NULL=0, + COLOR_WHITE, + COLOR_BLACK, + + COLOR_RED, + COLOR_YELLOW, + COLOR_LIMEGREEN, + COLOR_TURQUOISE, + COLOR_BLUE, + COLOR_BROWN, + COLOR_LIGHTGRAY, + COLOR_DARKGRAY, + + COLOR_GUIDE_BG +}; + +struct GamePad +{ + u16 trigger; + u16 release; + u16 button; + bool repeatTrigger; + u8 padding0; + int beginPress; +}; + +void Init(void); +void WaitVBlankIntr(void); +void dispOn(void); +void UpdateGamePad(void); +void UpdateDisplay(void); + +class CCanvas; +CCanvas* GetMain1Canvas(); +CCanvas* GetMain3Canvas(); +CCanvas* GetSub1Canvas(); +CCanvas* GetSub3Canvas(); + +inline u16 +IsPadDown(u16 key) +{ + extern GamePad System_GamePadState; + return static_cast(System_GamePadState.trigger & key); +} +inline u16 +IsPadUp(u16 key) +{ + extern GamePad System_GamePadState; + return static_cast(System_GamePadState.release & key); +} +inline u16 +IsPadPress(u16 key) +{ + extern GamePad System_GamePadState; + return static_cast(System_GamePadState.button & key); +} +inline u16 +IsPadTrigger(u16 key) +{ + extern GamePad System_GamePadState; + if( System_GamePadState.repeatTrigger ) + { + return IsPadPress(key); + } + else + { + return IsPadDown(key); + } +} + +u16 GetPadTrigger(); + +} // namespace util + +#endif // WIRELESS_CHECHER_UTIL_H_ diff --git a/build/tests/WirelessChecker/src/util/wprintf.cpp b/build/tests/WirelessChecker/src/util/wprintf.cpp new file mode 100644 index 00000000..35879971 --- /dev/null +++ b/build/tests/WirelessChecker/src/util/wprintf.cpp @@ -0,0 +1,387 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Nmenu + File: WPrintf.cpp + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "util/wprintf.h" + +namespace util +{ +namespace +{ + /* inner function for sized-buffer output */ + + typedef struct dst_string_tag + { + size_t len; + wchar_t *cur; + wchar_t *base; + } dst_string; + + void + string_put_char(dst_string *p, wchar_t c) + { + if(p->len > 0) *p->cur = c, --p->len; + ++p->cur; + } + + void + string_fill_char(dst_string *p, wchar_t c, int n) + { + if(n > 0) { + size_t i, k = p->len; + if(k > (size_t)n) k = (size_t)n; + for( i = 0 ; i < k ; ++i ) + p->cur[i] = c; + p->len -= k; + p->cur += n; + } + } + + void + string_put_string(dst_string *p, const wchar_t *s, int n) + { + if(n > 0) { + size_t i, k = p->len; + if(k > (size_t)n) k = (size_t)n; + for( i = 0 ; i < k ; ++i ) + p->cur[i] = s[i]; + p->len -= k; + p->cur += n; + } + } +} + +// based on OS_VSNPrintf + +/*---------------------------------------------------------------------------* + Name: OS_VSNPrintf + + Description: small-size vsnprintf which is similar to 'vsnprintf' + without following supports. + * CodeWarrior Extensions (#s) + * MSL AltiVec Extensions (v, vh, vl, hv, lv, @) + * indexed argments (%m$, *m$) + * floating-point + * wchar_t + + Note: '+' and '#' do not work, MSL's sprintf(). + to keep same result, they are no implement. + { // exsample + wchar_t buf[5]; + sprintf(buf, "%-i\n", 45); // "45" (OK) + sprintf(buf, "%0i\n", 45); // "45" (OK) + sprintf(buf, "% i\n", 45); // " 45" (OK) + sprintf(buf, "%+i\n", 45); // "%+i" ("+45" expected) + sprintf(buf, "%#x\n", 45); // "%#x" ("0x2d" expected) + // but, this works correctly! + sprintf(buf, "% +i\n", 45); // "+45" (OK) + } + + Arguments: dst : destination buffer. + len : destination buffer size. + fmt : format string. + vlist : parameters. + + Returns: length of the generated string. (except '\0') + if(result < len), + put NUL in dst[result]. + else if(len > 0), + put NUL in dst[len - 1]. + else, + do nothing. + *---------------------------------------------------------------------------*/ +int +VSNWPrintf(wchar_t *dst, size_t len, const wchar_t *fmt, va_list vlist) +{ + wchar_t buf[24]; + int n_buf; + wchar_t prefix[2]; + int n_prefix; + + const wchar_t *s = fmt; + + dst_string str; + str.len = len, str.cur = str.base = dst; + + while(*s) { + if(*s != L'%') { + /* normal character */ + string_put_char(&str, *s++); + } else { + /* output with format */ + enum { + flag_blank = 000001, /* L' ' */ + flag_plus = 000002, /* L'+' */ + flag_sharp = 000004, /* L'#' */ + flag_minus = 000010, /* L'-' */ + flag_zero = 000020, /* L'0' */ + flag_l1 = 000040, /* "l" */ + flag_h1 = 000100, /* "h" */ + flag_l2 = 000200, /* "ll" */ + flag_h2 = 000400, /* "hh" */ + flag_unsigned = 010000, /* L'o', L'u', ... */ + flag_end } ; + int flag = 0, width = 0, precision = -1, radix = 10; + wchar_t hex_char = L'a' - 10; + const wchar_t *p_start = s; + /* flags */ + for( ; ; ) { + switch(*++s) { + case L'+':if(s[-1] != L' ') break; + flag |= flag_plus; continue; + case L' ':flag |= flag_blank;continue; + case L'-':flag |= flag_minus;continue; + case L'0':flag |= flag_zero; continue; + } + break; + } + /* width */ + if(*s == L'*') { + ++s, width = va_arg(vlist, int); + if(width < 0) + width = -width, flag |= flag_minus; + } else { + while((*s >= L'0') && (*s <= L'9')) + width = (width * 10) + *s++ - L'0'; + } + /* precision */ + if(*s == L'.') { + ++s, precision = 0; + if(*s == L'*') { + ++s, precision = va_arg(vlist, int); + if(precision < 0) precision = -1; + } else { + while((*s >= L'0') && (*s <= L'9')) + precision = (precision * 10) + *s++ - L'0'; + } + } + /* option */ + switch(*s) { + case L'h': + if(*++s != L'h') flag |= flag_h1; + else ++s, flag |= flag_h2; + break; + case L'l': + if(*++s != L'l') flag |= flag_l1; + else ++s, flag |= flag_l2; + break; + } + + /* type */ + switch(*s) { + case L'd': /* signed decimal */ + case L'i': /* signed decimal */ + goto put_integer; + case L'o': /* unsigned octal */ + radix = 8; + flag |= flag_unsigned; + goto put_integer; + case L'u': /* unsigned decimal */ + flag |= flag_unsigned; + goto put_integer; + case L'X': /* unsigned hexadecimal */ + hex_char = L'A' - 10; + goto put_hexadecimal; + case L'x': /* unsigned hexadecimal */ + goto put_hexadecimal; + case L'p': /* pointer */ + /* equal to code warrior */ + flag |= flag_sharp; + precision = 8; + goto put_hexadecimal; + + case L'c': /* character */ + if(precision >= 0) + goto put_invalid; + { + int c = va_arg(vlist, int); + width -= 1; + if(flag & flag_minus) { + string_put_char(&str, (wchar_t)c); + string_fill_char(&str, L' ', width); + } else { + wchar_t pad = (wchar_t)( + (flag & flag_zero) ? L'0' : L' '); + string_fill_char(&str, pad, width); + string_put_char(&str, (wchar_t)c); + } + ++s; + } + break; + + case L's': /* string */ + { + int n_buf = 0; + const wchar_t *p_buf = va_arg(vlist, const wchar_t*); + if(precision < 0) { + while(p_buf[n_buf]) + ++n_buf; + } else { + while((n_buf < precision) && p_buf[n_buf]) + ++n_buf; + } + width -= n_buf; + if(flag & flag_minus) { + string_put_string(&str, p_buf, n_buf); + string_fill_char(&str, L' ', width); + } else { + wchar_t pad = (wchar_t)( + (flag & flag_zero) ? L'0' : L' '); + string_fill_char(&str, pad, width); + string_put_string(&str, p_buf, n_buf); + } + ++s; + } + break; + + case L'n': /* store the number of output */ + { + int pos = str.cur - str.base; + if(flag & flag_h2) + ; + else if(flag & flag_h1) + *va_arg(vlist, signed short*) = (signed short)pos; + else if(flag & flag_l2) + *va_arg(vlist, u64*) = (u64)pos; + else + *va_arg(vlist, signed int*) = (signed int)pos; + } + ++s; + break; + + case L'%': /* output L'%' */ + if(p_start + 1 != s) + goto put_invalid; + string_put_char(&str, *s++); + break; + + default: /* invalid type */ + goto put_invalid; + +put_invalid: + string_put_string(&str, p_start, s - p_start); + break; + +put_hexadecimal: + radix = 16; + flag |= flag_unsigned; +put_integer: + { + u64 val = 0; + n_prefix = 0; + + if(flag & flag_minus) + flag &= ~flag_zero; + if(precision < 0) precision = 1; + else flag &= ~flag_zero; + + if(flag & flag_unsigned) { + if(flag & flag_h2) + val = va_arg(vlist, wchar_t); + else if(flag & flag_h1) + val = va_arg(vlist, unsigned short); + else if(flag & flag_l2) + val = va_arg(vlist, u64); + else + val = va_arg(vlist, unsigned long); + flag &= ~(flag_plus | flag_blank); + if(flag & flag_sharp) { + if(radix == 16) { + if(val != 0) { + prefix[0] = (wchar_t)(hex_char + (10 + L'x' - L'a')); + prefix[1] = L'0'; + n_prefix = 2; + } + } else if(radix == 8) { + prefix[0] = L'0'; + n_prefix = 1; + } + } + } else { + if(flag & flag_h2) + val = va_arg(vlist, wchar_t); + else if(flag & flag_h1) + val = va_arg(vlist, short); + else if(flag & flag_l2) + val = va_arg(vlist, u64); + else + val = va_arg(vlist, long); + if((val >> 32) & 0x80000000) { + val = ~val + 1; + prefix[0] = L'-'; + n_prefix = 1; + } else { + if(val || precision) { + if(flag & flag_plus) { + prefix[0] = L'+'; + n_prefix = 1; + } else + if(flag & flag_blank) { + prefix[0] = L' '; + n_prefix = 1; + } + } + } + } + n_buf = 0; + while(val != 0) { + int d = (int)(val % radix); + val /= radix; + buf[n_buf++] = (wchar_t)((d < 10) ? + (d + L'0') : (d + hex_char)); + } + if((n_prefix > 0) && (prefix[0] == L'0')) { + n_prefix = 0; + buf[n_buf++] = L'0'; + } + } + goto put_to_stream; + +put_to_stream: + { + int n_pad = precision - n_buf; + if(flag & flag_zero) { + if(n_pad < width - n_buf - n_prefix) + n_pad = width - n_buf - n_prefix; + } + if(n_pad > 0) width -= n_pad; + width -= n_prefix + n_buf; + if(!(flag & flag_minus)) + string_fill_char(&str, L' ', width); + while(n_prefix > 0) + string_put_char(&str, prefix[--n_prefix]); + string_fill_char(&str, L'0', n_pad); + while(n_buf > 0) + string_put_char(&str, buf[--n_buf]); + if(flag & flag_minus) + string_fill_char(&str, L' ', width); + ++s; + } + break; + } + } + } + + if(str.len > 0) + *str.cur = '\0'; + else if(len > 0) + str.base[len - 1] = '\0'; + return str.cur - str.base; +} + + +} +// end of namespace tlib diff --git a/build/tests/WirelessChecker/src/util/wprintf.h b/build/tests/WirelessChecker/src/util/wprintf.h new file mode 100644 index 00000000..d63dff9f --- /dev/null +++ b/build/tests/WirelessChecker/src/util/wprintf.h @@ -0,0 +1,100 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - Nmenu + File: WPrintf.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef TLIB_SYSTEM_WPRINTF_H_ +#define TLIB_SYSTEM_WPRINTF_H_ + + + +namespace util +{ + +int VSNWPrintf(wchar_t *dst, size_t len, const wchar_t *fmt, va_list vlist); + + +/*---------------------------------------------------------------------------* + Name: OS_SNPrintf + + Description: equal to 'OS_VSNPrintf' except argument style. + + Arguments: dst : destination buffer. + len : destination buffer size. + fmt : format string. + + Returns: length of the generated string. (except '\0') + if(result < len), + put NUL in dst[result]. + else if(len > 0), + put NUL in dst[len - 1]. + else, + do nothing. + *---------------------------------------------------------------------------*/ +inline int +SNWPrintf(wchar_t *dst, size_t len, const wchar_t *fmt, ...) +{ + int ret; + va_list va; + va_start(va, fmt); + ret = VSNWPrintf(dst, len, fmt, va); + va_end(va); + return ret; +} + +/*---------------------------------------------------------------------------* + Name: OS_VSPrintf + + Description: equal to 'OS_VSNPrintf' except buffer size argument. + + Arguments: dst : destination buffer. + fmt : format string. + vlist : parameters. + + Returns: length of the generated string. + *---------------------------------------------------------------------------*/ +inline int +VSWPrintf(wchar_t *dst, const wchar_t *fmt, va_list vlist) +{ + return VSNWPrintf(dst, 0x7FFFFFFF, fmt, vlist); +} + +/*---------------------------------------------------------------------------* + Name: OS_SPrintf + + Description: equal to 'OS_VSPrintf' except argument style. + + Arguments: dst : destination buffer. + fmt : format string. + + Returns: length of the generated string. + *---------------------------------------------------------------------------*/ +inline int +SWPrintf(wchar_t *dst, const wchar_t *fmt, ...) +{ + int ret; + va_list va; + va_start(va, fmt); + ret = VSWPrintf(dst, fmt, va); + va_end(va); + return ret; +} + + +} +// end of namespace tlib + + + +#endif // TLIB_SYSTEM_WPRINTF_H_