Многие из счастливых обладателей PSP, читающих ][, наверняка не раз задумывались: вот прогаю я для компа, или взламываю всякие сайты — а вот клево было бы написать что-нибудь для своей приставки. Например, ММОРПГ — при наличии Wi-Fi, неплохих графических возможностей и удобного управления, созданного специально для игр, в этой нише у карманной игровой станции странная пустота. Или тулзу для взлома Wi-Fi сетей. Или брутер, который можно спокойно оставить на ночь — потому что он не шумит, не жрет много электричества и не кишит вирусами (кстати, тоже ведь идея!). Тем более, к PSP теперь можно подсоединить всяческие фотоаппараты и микрофоны — в общем, гуляй — не хочу.


Фото: uncle_lag

Как обычно зловещая корпорация не хочет, чтобы под их консоль штамповали игры, не отчисляя ей ни копейки — тем более, основной доход идет именно с процентов от продажи игр, а приставки частенько продаются по себестоимости, или даже в убыль. Поэтому абсолютно легально не получится не то что написать программу — да даже ее и запустить. Слава хакерам — нашлись умельцы, давно взломавшие зловещую прошивку приставки и убравшие из нее защиту (заодно врубив эмуляцию iso-образов игр, потому что UMD-диски дороговато стоят… но я вам этого не говорил ;)). Как получить такую версию прошивки расскажет pspfaqs.ru. Иди на этот сайт и перепрошивайся до
3.90 М33-3, и не забудь установить ядро 1.50 (если у тебя "толстая" версия консоли) — иначе то, что у нас получится, вполне может и не запуститься. Так что я буду считать, что ты это уже сделал, и останавливаться на этом не стану.

Также тебе понадобится карточка MemoryStick Duo. Идущая в комплекте должна вполне подойти, хотя я бы посоветовал купить хотя бы на 2 гигабайта — для программирования это очень много, но образы некоторых игр весят больше 1 Гб. Понадобится и шнур для соединения компа с приставкой (тоже есть в комплекте, а если уже потерял — что, ты не найдешь Usb-2-MiniUsb?). Еще из хардваре пригодится холодный, незамутненный разум хирурга, а то вскрытие (программное, корпус открывать не будем) может завершиться смертью или сумасшествием пациента.

Кстати, предупреждаю сразу: ни я, ни редакция, ни — тем более — Sony не дает никаких гарантий, что с приставкой все будет хорошо в результате наших анатомических исследований. Она вполне может брикнуться (так бывалые псп-геймеры называют таинственное превращение клевой приставки в черный, белый, розовый — нужное подчеркнуть кирпич), заглючить, убить твою карточку MemoryStick или, превратившись в НЛО, улететь на Луну оставлять там  будоражащие кровь в жилах надписи.

Но ни у меня, ни у тех на ком я ставил свои противоестественные опыты, ничего такого не случилось. Самое страшное, что было — это зависание намертво, которое лечится обычным аварийным выключением: задержи рычажок выключения в позиции Power секунд на 6-7, пока зеленая лампочка не перестанет мигать. Теперь можешь включать.

В блокноте получается писать только на JavaScript’е, что для наших целей не особо подходит, поэтому придется скачать IDE и набор компиляторов. IDE я рекомендую Code::Blocks — именно для этой IDE я опишу процесс настройки, а набор компиляторов, под названием DevKitPSP. Я распаковал DevKitPSP в корень диска E:, так, что у меня теперь есть папка E:\devkitpsp\, а в ней папки bin, include и другие, и настройки буду указывать для этого пути — соответственно, если у тебя путь окажется другой, его придется везде
заменять. IDE можно установить куда угодно, после чего запусти его и настрой (буду давать сведения по настройке максимально сжато потому, что их много. Утешает то, что придется сделать это один раз):

1. Settings — Compiler and Debugger, Selected Compiler: GNU GCC, жмем Copy, называем копию DevKitPSP, выбираем ее в списке компиляторов.

2. В том же окне — вкладка Search Directories — Compiler должна содержать только:

E:\devkitPSP\include
E:\devkitPSP\psp\include
E:\devkitPSP\psp\sdk\include
Search Directories — Linker:
E:\devkitPSP\lib
E:\devkitPSP\psp\lib
E:\devkitPSP\psp\sdk\lib

3. Вкладка Toolchain Executables:

Compiler’s installation directory: E:\devkitPSP
C-compiler: psp-gcc.exe
C++-compiler: psp-g++.exe
Linker for dynamic libs: psp-g++.exe
Linker for static libs: psp-ar.exe

Еще три поля там же оставляем пустыми, и жмем ОК.

4. Создаем проект: File-New-Project…, Projects, Empty. Project Title пусть будет PSPHelloWorld, указываем папку для сохранения проекта где-нибудь на компьютере; компилятор ставим DevKitPSP.

5. Cоздаем фаил File>New>File…, main.c — в мастере создания фаила выбираем язык Си и ставим галочки "Add to current project", "Debug" и "Release".

6. В созданный фаил копируем код из архива. Попозже разберемся, что он делает, а пока — донастроим проект и запустим его.

7. Project-Properties, Build targets. Снимаем галочку "Auto-generate filename extension", и правим в Output filename расширение "exe" на "elf". Выполняем тоже самое для конфигурации Release, жмем Ok.

8. Project-Build Options, Linker Options, Other linker options:

-lpspdebug -lpspdisplay -lpspge -lpspctrl -lpspsdk -lpsplibc -lpspnet_inet -lpspnet_apctl -lpspnet_resolver -lpsputility -lpspuser -lpspkernel

Повторяем для Release.

Ура! Можно жать на Build-Build и собирать проект, надеюсь — без ошибок. Так мы получим elf-файл с программой. Но эльфы "грабят корованы" в юниксах, а у нас странная ОС от PSP, готовая исполнять лишь файлы с милым русскому человеку названием EBOOT.PBP. Для выполнения сложной операции преобразования у меня есть волшебный bat-ник:

"E:\devkitPSP\bin\mksfo.exe" %1 %1.sfo
"E:\devkitPSP\bin\psp-fixup-imports.exe" %1.elf
"E:\devkitPSP\bin\psp-strip.exe" %1.elf -o stripped.elf
"E:\devkitPSP\bin\pack-pbp.exe" EBOOT.PBP %1.sfo NULL NULL NULL NULL NULL stripped.elf NULL

Разумеется, запускать его надо с аргументом-именем твоего elf-фаила (без расширения). Т.е., если у тебя получился HelloWorld.elf, то запускай батник как my_batnik.bat HelloWorld. Ну а если ты противник таких вещей — можешь вводить содержимое по строчке в консоль, заменяя %1 на имя того файла.

Теперь у нас есть долгожданный EBOOT, и его мы пихаем в папку /PSP/GAME150/HelloWorld/ нашей PSP-шки. После чего запускаем его, громогласно приветствуя мир. Поздравляю! Вы написали свою первую программу на PSP. Прежде чем закрывать IDE, советую сохранить проект как шаблон (File-Save Project as user-template…) — чтобы потом, при создании нового, не начинать все заново.

Как ты уже наверное понял, функция pspDebugScreenPrintf() выводит текст на экран. Она — полный аналог функции printf() и поддерживает ее форматную строку. Я начал описывать код с нее, так как это — первая функция, которой учат несчастных, изучающих Си. Вторая же изучаемая функция — обычно scanf(), но ее для PSP нет — потому что нет клавиатуры. Поэтому я просто расскажу, как получать состояние кнопок и джойстика.

За кнопки отвечает функция sceCtrlReadBufferPositive, описанная в фаиле pspctrl.h, так что добавляем в начало main.c строку:

#include <pspctrl.h>

В качестве параметров функция принимает указатель на структуру SceCtrlData, в которую она возвратит данные о кнопках, и количество буферов для чтения, так что вызывать мы ее будем так:

SceCtrlData pad;
sceCtrlReadBufferPositive(&pad, 1);

Вот описание возвращаемой структуры:

typedef struct SceCtrlData {
unsigned int TimeStamp; // читаемый фрейм
unsigned int Buttons; // битовая маска, задающая кнопки
unsigned char Lx;
unsigned char Ly; // положение джойстика
unsigned char Rsrv[6]; // зарезервировано
} SceCtrlData;

А вот — список кнопок, состояние которых появляется в битовой маске SceCtrlData::Buttons:

enum PspCtrlButtons
{
PSP_CTRL_SELECT = 0x000001,
PSP_CTRL_START = 0x000008,
PSP_CTRL_UP = 0x000010,
PSP_CTRL_RIGHT = 0x000020,
PSP_CTRL_DOWN = 0x000040,
PSP_CTRL_LEFT = 0x000080,
PSP_CTRL_LTRIGGER = 0x000100,
PSP_CTRL_RTRIGGER = 0x000200,
PSP_CTRL_TRIANGLE = 0x001000,
PSP_CTRL_CIRCLE = 0x002000,
PSP_CTRL_CROSS = 0x004000,
PSP_CTRL_SQUARE = 0x008000,
PSP_CTRL_HOME = 0x010000,
PSP_CTRL_HOLD = 0x020000,
PSP_CTRL_NOTE = 0x800000,
//
читается только в режиме ядра, т.е.
//
не судьба нам узнать о нажатии на нее
PSP_CTRL_SCREEN = 0x400000, //
только в режиме ядра
PSP_CTRL_VOLUP = 0x100000, //
только в режиме ядра
PSP_CTRL_VOLDOWN = 0x200000, //
только в режиме ядра
PSP_CTRL_WLAN_UP = 0x040000, //
только в режиме ядра
PSP_CTRL_REMOTE = 0x080000, //
только в режиме ядра
PSP_CTRL_DISC = 0x1000000, //
только в режиме ядра
PSP_CTRL_MS = 0x2000000, //
только в режиме ядра
};

Как использовать эти странные числа? А очень просто. Чтобы узнать, нажата ли, скажем, кнопка с кружочком, нам надо проверить (pad.Buttons & PSP_CTRL_CIRCLE). Т.е., например:

if (pad.Buttons & PSP_CTRL_CIRCLE)
pspDebugScreenPrintf("CIRCLE PRESSED");

А как использовать джойстик, можно догадаться и самому. Надо только знать, что координаты его положения меняются от 0 до 255 (значит, середина — в точке (128,128)), и не забывать, что он редко стоит прямо по центру (на отклонение в несколько единиц лучше не обращать внимания, позже ты увидишь, почему). Кстати, чтобы информация о положении джойстика приходила, необходимо добавить вот такие строки:

sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);

Все. Теперь мы знаем о кнопках все, что можем. И для примера можно написать несложную программу, которая будет показывать, что в данный момент нажато. Вот что получилось у меня (я, кстати, поленился и стал мониторить только кнопки с рисунками, т.е. крестик, кружок, треугольник и квадрат. Но не думаю, что у тебя возникнут какие-то проблемы с этим):

SceCtrlData pad;

int main(int argc, char ** argv)
{
pspDebugScreenInit();

// устанавливаем каллбеки
SetupCallbacks();

sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
//
настраиваем на прием информации о положении стика

while(1) // главный цикл программы
{
pspDebugScreenClear(); //
чистим экран
sceCtrlReadBufferPositive(&pad, 1);
//
читаем содержимое буфера э-э клавиатуры
pspDebugScreenPrintf("TimeStamp %i | Pressed: ", pad.TimeStamp);
//
выводим TimeStamp
if (pad.Buttons == 0) //
ничего не нажато
{
pspDebugScreenPrintf("NONE ");
} else {
if (pad.Buttons & PSP_CTRL_TRIANGLE) pspDebugScreenPrintf("TRIANGLE ");
if (pad.Buttons & PSP_CTRL_CIRCLE) pspDebugScreenPrintf("CIRCLE ");
if (pad.Buttons & PSP_CTRL_CROSS) pspDebugScreenPrintf("CROSS ");
if (pad.Buttons & PSP_CTRL_SQUARE) pspDebugScreenPrintf("SQUARE ");
//
какие кнопки нажаты?
}
pspDebugScreenPrintf("(%i) | Stick: %i:%i\n", pad.Buttons, pad.Lx, pad.Ly);
//
выводим координаты стика
}

sceKernelSleepThread();
//
поток засыпает
//
если уснули все потоки, то единственное,
//
что может случиться - это каллбек
//
в этой программе эта строчка никогда не выполнится ;)

return 0;
}

Все остальные функции лучше оставить такими, какие есть. Полную версию этой программы с комментарием к каждой строчке можно найти в архиве.

Итак, мы можем теперь выводить что угодно и узнавать, как на это реагирует пользователь. Самое время портировать Moria или какую-нибудь змейку 🙂 Для полного текстового счастья не хватает, конечно же, цвета и возможности писать где угодно. Ради цвета я бы посоветовал использовать макрос, который я благополучно стырил откуда-то из хедеров к IDE:

typedef unsigned char byte;
//
определяем, потому что DevKitPSP понятия не имеет,
//
что есть такой тип
#define RGB(r,g,b) ((u32)((byte)(r)|((byte)(g) << 8)|((byte)(b) << 16)))

Этот макрос выдает цвет, подходящий к любым функциям, связанным с цветом среди API PSP. Например, к функции установки фона для текста:

pspDebugScreenSetBackColor(RGB(0, 0, 255));
//
ставим синий

или цвета самого текста:

pspDebugScreenSetTextColor(RGB(0, 255, 0));
//
зеленый!

или даже установки символа в любую позицию:

pspDebugScreenPutChar(100, 100, RGB(255, 0, 0), 'A');
//
ставим красный символ 'A' в точку с координатами (100, 100)

Кстати, координаты задаются в пикселях, а не в строках и столбцах символов.

Ну что ж, теперь ты можешь написать на экране PSP что угодно. Например, проклятие черными буквами на черном фоне своему врагу, или другу-готу. Или розовым по черному нарисовать ASCII-спанч боба. Или красным по розовому признаться в любви своей девушке (парню?). Или… а, о чем я. Решать тебе. Наслаждайся! А в следующей статье я постараюсь рассказать про картинки. Хотя бы немножко 😉

И на последок: советую подписаться на мой блог, http://psp.va1en0k.net/. Там я буду выкладывать много материала, полезного для PSP-программиста 😉

Оставить мнение

Check Also

LUKS container vs Border Patrol Agent. Как уберечь свои данные, пересекая границу

Не секрет, что если ты собрался посетить такие страны как США или Великобританию то, прежд…