minor psp fixes
[libpicofe.git] / psp / psp.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
5
6 #include <pspkernel.h>
7 #include <pspiofilemgr.h>
8 #include <pspdisplay.h>
9 #include <psppower.h>
10 #include <psprtc.h>
11 #include <pspgu.h>
12
13 #include "psp.h"
14 #include "emu.h"
15 #include "../common/lprintf.h"
16
17 PSP_MODULE_INFO("PicoDrive", 0, 1, 34);
18 PSP_HEAP_SIZE_MAX();
19
20 unsigned int __attribute__((aligned(16))) guCmdList[GU_CMDLIST_SIZE];
21
22 void *psp_screen = VRAM_FB0;
23 static int current_screen = 0; /* front bufer */
24
25 static SceUID main_thread_id = -1;
26
27 #define ANALOG_DEADZONE 80
28
29 /* Exit callback */
30 static int exit_callback(int arg1, int arg2, void *common)
31 {
32         sceKernelExitGame();
33         return 0;
34 }
35
36 /* Power Callback */
37 static int power_callback(int unknown, int pwrflags, void *common)
38 {
39         /* check for power switch and suspending as one is manual and the other automatic */
40         if (pwrflags & PSP_POWER_CB_POWER_SWITCH || pwrflags & PSP_POWER_CB_SUSPENDING)
41         {
42                 lprintf("power_callback: flags: 0x%08X: suspending\n", pwrflags);
43                 engineState = PGS_Menu;
44         }
45         sceDisplayWaitVblankStart();
46         return 0;
47 }
48
49 /* Callback thread */
50 static int callback_thread(SceSize args, void *argp)
51 {
52         int cbid;
53
54         lprintf("callback_thread started with id %08x, priority %i\n",
55                 sceKernelGetThreadId(), sceKernelGetThreadCurrentPriority());
56
57         cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
58         sceKernelRegisterExitCallback(cbid);
59         cbid = sceKernelCreateCallback("Power Callback", power_callback, NULL);
60         scePowerRegisterCallback(0, cbid);
61
62         sceKernelSleepThreadCB();
63
64         return 0;
65 }
66
67 void psp_init(void)
68 {
69         SceUID thid;
70
71         main_thread_id = sceKernelGetThreadId();
72
73         lprintf("running on %08x kernel\n", sceKernelDevkitVersion()),
74         lprintf("entered psp_init, threadId %08x, priority %i\n", main_thread_id,
75                 sceKernelGetThreadCurrentPriority());
76
77         thid = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, 0);
78         if (thid >= 0)
79         {
80                 sceKernelStartThread(thid, 0, 0);
81         }
82
83         /* video */
84         sceDisplaySetMode(0, 480, 272);
85         sceDisplaySetFrameBuf(VRAM_FB1, 512, PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
86         current_screen = 1;
87         psp_screen = VRAM_FB0;
88
89         /* gu */
90         sceGuInit();
91
92         sceGuStart(GU_DIRECT, guCmdList);
93         sceGuDrawBuffer(GU_PSM_5650, (void *)VRAMOFFS_FB0, 512);
94         sceGuDispBuffer(480, 272, (void *)VRAMOFFS_FB1, 512); // don't care
95         sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT);
96         sceGuDepthBuffer((void *)VRAMOFFS_DEPTH, 512);
97         sceGuOffset(2048 - (480 / 2), 2048 - (272 / 2));
98         sceGuViewport(2048, 2048, 480, 272);
99         sceGuDepthRange(0xc350, 0x2710);
100         sceGuScissor(0, 0, 480, 272);
101         sceGuEnable(GU_SCISSOR_TEST);
102
103         sceGuDepthMask(0xffff);
104         sceGuDisable(GU_DEPTH_TEST);
105
106         sceGuFrontFace(GU_CW);
107         sceGuEnable(GU_TEXTURE_2D);
108         sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
109         sceGuAmbientColor(0xffffffff);
110         sceGuColor(0xffffffff);
111         sceGuFinish();
112         sceGuSync(0, 0);
113
114         sceDisplayWaitVblankStart();
115         sceGuDisplay(GU_TRUE);
116
117
118         /* input */
119         sceCtrlSetSamplingCycle(0);
120         sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
121 }
122
123 void psp_finish(void)
124 {
125         sceGuTerm();
126
127         //sceKernelSleepThread();
128         sceKernelExitGame();
129 }
130
131 void psp_video_flip(int wait_vsync)
132 {
133         if (wait_vsync) sceDisplayWaitVblankStart();
134         sceDisplaySetFrameBuf(psp_screen, 512, PSP_DISPLAY_PIXEL_FORMAT_565,
135                 wait_vsync ? PSP_DISPLAY_SETBUF_IMMEDIATE : PSP_DISPLAY_SETBUF_NEXTFRAME);
136         current_screen ^= 1;
137         psp_screen = current_screen ? VRAM_FB0 : VRAM_FB1;
138 }
139
140 void *psp_video_get_active_fb(void)
141 {
142         return current_screen ? VRAM_FB1 : VRAM_FB0;
143 }
144
145 void psp_video_switch_to_single(void)
146 {
147         psp_screen = VRAM_FB0;
148         sceDisplaySetFrameBuf(psp_screen, 512, PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
149         current_screen = 0;
150 }
151
152 void psp_msleep(int ms)
153 {
154         sceKernelDelayThread(ms * 1000);
155 }
156
157 unsigned int psp_pad_read(int blocking)
158 {
159         unsigned int buttons;
160         SceCtrlData pad;
161         if (blocking)
162              sceCtrlReadBufferPositive(&pad, 1);
163         else sceCtrlPeekBufferPositive(&pad, 1);
164         buttons = pad.Buttons;
165
166         // analog..
167         buttons &= ~(BTN_NUB_UP|BTN_NUB_DOWN|BTN_NUB_LEFT|BTN_NUB_RIGHT);
168         if (pad.Lx < 128 - ANALOG_DEADZONE) buttons |= BTN_NUB_LEFT;
169         if (pad.Lx > 128 + ANALOG_DEADZONE) buttons |= BTN_NUB_RIGHT;
170         if (pad.Ly < 128 - ANALOG_DEADZONE) buttons |= BTN_NUB_UP;
171         if (pad.Ly > 128 + ANALOG_DEADZONE) buttons |= BTN_NUB_DOWN;
172
173         return buttons;
174 }
175
176 int psp_get_cpu_clock(void)
177 {
178         return scePowerGetCpuClockFrequencyInt();
179 }
180
181 int psp_set_cpu_clock(int clock)
182 {
183         int ret = scePowerSetClockFrequency(clock, clock, clock/2);
184         if (ret != 0) lprintf("failed to set clock: %i\n", ret);
185
186         return ret;
187 }
188
189 char *psp_get_status_line(void)
190 {
191         static char buff[64];
192         int ret, bat_percent, bat_time;
193         pspTime time;
194
195         ret = sceRtcGetCurrentClockLocalTime(&time);
196         bat_percent = scePowerGetBatteryLifePercent();
197         bat_time = scePowerGetBatteryLifeTime();
198         if (ret < 0 || bat_percent < 0 || bat_time < 0) return NULL;
199
200         snprintf(buff, sizeof(buff), "%02i:%02i  bat: %3i%%", time.hour, time.minutes, bat_percent);
201         if (!scePowerIsPowerOnline())
202                 snprintf(buff+strlen(buff), sizeof(buff)-strlen(buff), " (%i:%02i)", bat_time/60, bat_time%60);
203         return buff;
204 }
205
206 /* alt logging */
207 #define LOG_FILE "log.txt"
208
209 typedef struct _log_entry
210 {
211         char buff[256];
212         struct _log_entry *next;
213 } log_entry;
214
215 static log_entry *le_root = NULL;
216
217 void lprintf_f(const char *fmt, ...)
218 {
219         va_list vl;
220
221 #ifdef LPRINTF_STDIO
222         va_start(vl, fmt);
223         vprintf(fmt, vl);
224         va_end(vl);
225 #else
226         static SceUID logfd = -1;
227         char buff[256];
228         log_entry *le, *le1;
229
230         if (logfd == -2) return; // disabled
231
232         va_start(vl, fmt);
233         vsnprintf(buff, sizeof(buff), fmt, vl);
234         va_end(vl);
235
236         // note: this is still unsafe code
237         if (main_thread_id != sceKernelGetThreadId())
238         {
239                 le = malloc(sizeof(*le));
240                 if (le == NULL) return;
241                 le->next = NULL;
242                 strcpy(le->buff, buff);
243                 if (le_root == NULL) le_root = le;
244                 else {
245                         for (le1 = le_root; le1->next != NULL; le1 = le1->next);
246                         le1->next = le;
247                 }
248                 return;
249         }
250
251         logfd = sceIoOpen(LOG_FILE, PSP_O_WRONLY|PSP_O_APPEND, 0777);
252         if (logfd < 0) {
253                 logfd = -2;
254                 return;
255         }
256
257         if (le_root != NULL)
258         {
259                 le1 = le_root;
260                 le_root = NULL;
261                 sceKernelDelayThread(1000);
262                 while (le1 != NULL) {
263                         le = le1;
264                         le1 = le->next;
265                         sceIoWrite(logfd, le->buff, strlen(le->buff));
266                         free(le);
267                 }
268         }
269
270         sceIoWrite(logfd, buff, strlen(buff));
271
272         // make sure it gets flushed
273         sceIoClose(logfd);
274         logfd = -1;
275 #endif
276 }
277
278