Користувачі PlayStation Portable
Багато хто з щасливих власників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, поки зелена лампочка не перестане блимати. Тепер можеш вмикати.
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 Linkerfor static libs: psp-ar.exe
Ще три поля там же залишаємо порожніми і тиснемо ОК.
4. Створюємо проект: File-New-Project…, Projects, Empty. Project Title нехай буде PSPHelloWorld, вказуємо папку для збереження проекту десь на комп'ютері; компілятор ставимо DevKitPSP.
5. Створюємо фаїл 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 рядок:
В якості параметрів функція приймає покажчик на структуру SceCtrlData, в яку вона поверне дані про кнопки, і кількість буферів для читання, так що ми її викликатимемо так:
SceCtrlData pad; sceCtrlReadBufferPositive(&pad 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 = 0x0000040>PSP_CTRL_LTRIGGER = 0x000100, PSP_CTRL_RTRIGGER = 0x000200 , PSP_CTRL_TRIANGLE = 0x001000, PSP_CTRL_CIRCLE = 0x002000, PSP_CTRL_CROSS = 0x004000, PSP_CTRL_SQUARE = 0x008000, 0 SP_CTRL_HOLD = 0x020000, PSP_CTRL_NOTE = 0x800000, // читається лише режимі ядра, тобто. // не доля нам дізнатися про натискання на неї PSP_CTRL_SCREEN = 0x400000 // тільки в режимі ядра PSP_CTRL_VOLUP = 0x100000 // тільки в режимі ядра PSP_CTRL_VOLDOWN = 0x2 режиме ядра PSP_CTRL_WLAN_UP = 0x040000, // только в режиме ядра PSP_CTRL_REMOTE = 0x080000, // только в режиме ядра PSP_CTRL_DISC = 0x1000000, // только в режиме ядра PSP_CTRL_MS = 0x2000000, // лише у режимі ядра >;
Як використати ці дивні числа? А дуже просто. Щоб дізнатися, чи натиснута, скажімо, кнопка з кружечком, нам треба перевірити (pad.Buttons & PSP_CTRL_CIRCLE). Тобто, наприклад:
А як використати джойстик, можна здогадатися і самому. Треба тільки знати, що координати його положення змінюються від 0 до 255 (означає, середина — у точці (128,128)), і не забувати, що він рідко стоїть прямо по центру (на відхилення в кілька одиниць краще не звертати уваги, пізніше ти побачиш чому). До речі, щоб інформація про положення джойстика надходила, необхідно додати такі рядки:
Всі. Тепер ми знаємо про кнопки все, що можемо. І для прикладу можна написати нескладну програму, яка показуватиме, що зараз натиснуто. Ось що вийшло у мене (я, до речі, полінувався і став моніторити лише кнопки з малюнками, тобто хрестик, кружок, трикутник та квадрат).Але не думаю, що в тебе виникнуть якісь проблеми із цим):
int main(int argc, char ** argv) pspDebugScreenInit();
// встановлюємо каллбеки SetupCallbacks();
sceCtrlSetSamplingCycle(0); sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG); // налаштовуємо на прийом інформації про положення стику
while(1) // головний цикл програми pspDebugScreenClear(); // чистимо екран sceCtrlReadBufferPositive(&padpad, 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(); // потік засинає // якщо заснули всі потоки, то єдине, // що може статися - це каллбек // у цій програмі цей рядок ніколи не виконається ;)
Отже, ми можемо тепер виводити будь-що і дізнаватися, як на це реагує користувач. Саме час портувати Moria або якусь змійку 🙂 Для повного текстового щастя не вистачає, звичайно ж, кольору та можливості писати де завгодно. Заради кольору я б порадив використати макрос, який я благополучно стирав звідкись із хедерів до IDE:
typedef unsigned char byte; // визначаємо, тому що DevKitPSP поняття не має, //що такий тип #define RGB(r,g,b) ((u32)((byte)(r)((byte)(g)
Цей макрос видає колір, що підходить до будь-яких функцій, пов'язаних із кольором серед 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-спанч боба. Або червоним по рожевому зізнатися у коханні своїй дівчині (хлопцю?). Або ... а, про що я. Вирішувати тобі. Насолоджуйся! А в наступній статті я намагатимусь розповісти про картинки. Хоча б трохи 😉