1 #include <PalmOS.h>
2 #include <stdint.h>
3
4 #include "ugui.h"
5 #include "testSuiteConfig.h"
6 #include "testSuite.h"
7 #include "viewer.h"
8 #include "debug.h"
9 #include "tools.h"
10
11 /*dont include this anywhere else*/
12 #include "TstSuiteRsc.h"
13
14
15 /*exported functions, cant be converted into macros*/
makeVar(uint8_t length,uint8_t type,uint64_t value)16 var makeVar(uint8_t length, uint8_t type, uint64_t value){
17 var newVar;
18 newVar.type = length & 0xF0 | type & 0x0F;
19 newVar.value = value;
20 return newVar;
21 }
22
23 static char floatString[maxStrIToALen * 2 + 3];/*2 ints and "-.\0"*/
floatToString(float data)24 char* floatToString(float data){
25 if(data == 1.0 / 0.0){
26 StrCopy(floatString, "+INF");
27 }
28 else if(data == -(1.0 / 0.0)){
29 StrCopy(floatString, "-INF");
30 }
31 else if(data == 0.0){
32 StrCopy(floatString, "0.0");
33 }
34 else{
35 char convertBuffer[maxStrIToALen];
36 Boolean negative;
37
38 if(data < 0.0){
39 negative = true;
40 data = -data;
41 }
42 else{
43 negative = false;
44 }
45
46 floatString[0] = '\0';
47 data = abs(data);
48 StrIToA(convertBuffer, (int32_t)data);
49 if(negative)
50 StrCat(floatString, "-");
51 StrCat(floatString, convertBuffer);
52 StrCat(floatString, ".");
53 data -= (int32_t)data;
54 data *= 1000000000;
55 StrIToA(convertBuffer, (int32_t)data);
56 StrCat(floatString, convertBuffer);
57 }
58
59 return floatString;
60 }
61
62 /*exports*/
63 uint16_t palmButtons;
64 uint16_t palmButtonsLastFrame;
65 Boolean isM515;
66 Boolean isT3;
67 Boolean skipFrameDelay;
68 uint8_t* sharedDataBuffer;
69
70 /*video*/
71 static UG_GUI uguiStruct;
72 static BitmapType* offscreenBitmap;
73 static uint8_t* framebuffer;
74
75 /*other*/
76 static activity_t parentSubprograms[MAX_SUBPROGRAMS];
77 static uint32_t subprogramIndex;
78 static activity_t currentSubprogram;
79 static var subprogramData[MAX_SUBPROGRAMS];
80 static var subprogramArgs;/*optional arguments when one subprogram calls another*/
81 static var lastSubprogramReturnValue;
82 static Boolean subprogramArgsSet;
83 static Boolean applicationRunning;
84
85
errorSubprogramStackOverflow(void)86 static var errorSubprogramStackOverflow(void){
87 static Boolean wipedScreen = false;
88
89 if(!wipedScreen){
90 debugSafeScreenClear(C_WHITE);
91 UG_PutString(0, 0, "Subprogram stack overflow!\nYou must close the program.");
92 wipedScreen = true;
93 }
94 if(getButtonPressed(buttonBack)){
95 /*force kill when back pressed*/
96 applicationRunning = false;
97 }
98 /*do nothing, this is a safe crash*/
99 }
100
memoryAllocationError(void)101 var memoryAllocationError(void){
102 static Boolean wipedScreen = false;
103
104 if(!wipedScreen){
105 debugSafeScreenClear(C_WHITE);
106 UG_PutString(0, 0, "Could not allocate memory!\nYou must close the program.");
107 wipedScreen = true;
108 }
109 if(getButtonPressed(buttonBack)){
110 /*force kill when back pressed*/
111 applicationRunning = false;
112 }
113 /*do nothing, this is a safe crash*/
114 }
115
uguiDrawPixel(UG_S16 x,UG_S16 y,UG_COLOR color)116 static void uguiDrawPixel(UG_S16 x, UG_S16 y, UG_COLOR color){
117 /*using 1bit grayscale*/
118 int pixel = x + y * SCREEN_WIDTH;
119 int byte = pixel / 8;
120 int bit = pixel % 8;
121
122 /*ugui will call this function even if its over the screen bounds, dont let those writes through*/
123 if(pixel > SCREEN_WIDTH * SCREEN_HEIGHT - 1)
124 return;
125
126 if(!color){
127 /*1 is black not white*/
128 framebuffer[byte] |= (1 << (7 - bit));
129 }
130 else{
131 framebuffer[byte] &= ~(1 << (7 - bit));
132 }
133 }
134
135 /*needed to redraw after every call to setDebugTag(char*)*/
forceFrameRedraw(void)136 void forceFrameRedraw(void){
137 WinDrawBitmap(offscreenBitmap, 0, 0);
138 }
139
callSubprogram(activity_t activity)140 void callSubprogram(activity_t activity){
141 if(subprogramIndex < MAX_SUBPROGRAMS - 1){
142 subprogramIndex++;
143 parentSubprograms[subprogramIndex] = activity;
144 currentSubprogram = activity;
145 if(!subprogramArgsSet)
146 subprogramArgs = makeVar(LENGTH_0, TYPE_NULL, 0);
147 subprogramArgsSet = false;/*clear to prevent next subprogram called from inheriting the args*/
148 setDebugTag("Subprogram Called");
149 }
150 else{
151 currentSubprogram = errorSubprogramStackOverflow;
152 /*cant recover from this*/
153 }
154 }
155
exitSubprogram(void)156 void exitSubprogram(void){
157 if(subprogramIndex > 0){
158 subprogramIndex--;
159 currentSubprogram = parentSubprograms[subprogramIndex];
160 setDebugTag("Subprogram Exited");
161 }
162 else{
163 /*last subprogram is complete*/
164 setDebugTag("Application Exiting");
165 applicationRunning = false;
166 }
167 }
168
execSubprogram(activity_t activity)169 void execSubprogram(activity_t activity){
170 if(!subprogramArgsSet)
171 subprogramArgs = makeVar(LENGTH_0, TYPE_NULL, 0);
172 subprogramArgsSet = false;/*clear to prevent next subprogram called from inheriting the args*/
173 currentSubprogram = activity;
174 setDebugTag("Subprogram Swapped Out");
175 }
176
getSubprogramReturnValue(void)177 var getSubprogramReturnValue(void){
178 return lastSubprogramReturnValue;
179 }
180
getSubprogramArgs(void)181 var getSubprogramArgs(void){
182 return subprogramArgs;
183 }
184
setSubprogramArgs(var args)185 void setSubprogramArgs(var args){
186 subprogramArgs = args;
187 subprogramArgsSet = true;
188 }
189
subprogramGetData(void)190 var subprogramGetData(void){
191 return subprogramData[subprogramIndex];
192 }
193
subprogramSetData(var data)194 void subprogramSetData(var data){
195 subprogramData[subprogramIndex] = data;
196 }
197
testerInit(void)198 static Boolean testerInit(void){
199 uint32_t osVer;
200 uint32_t deviceId;
201 Err error;
202
203 FtrGet(sysFtrCreator, sysFtrNumROMVersion, &osVer);
204 if(osVer < PalmOS35){
205 FrmCustomAlert(alt_err, "TestSuite requires at least PalmOS 3.5", 0, 0);
206 return false;
207 }
208
209 sharedDataBuffer = MemPtrNew(SHARED_DATA_BUFFER_SIZE);
210 if(!sharedDataBuffer){
211 FrmCustomAlert(alt_err, "Cant create memory buffer", 0, 0);
212 return false;
213 }
214
215 offscreenBitmap = BmpCreate(SCREEN_WIDTH, SCREEN_HEIGHT, 1, NULL, &error);
216 if(error != errNone){
217 FrmCustomAlert(alt_err, "Cant create bitmap", 0, 0);
218 return false;
219 }
220
221 KeySetMask(~(keyBitPageUp | keyBitPageDown | keyBitHard1 | keyBitHard2 | keyBitHard3 | keyBitHard4 ));
222
223 framebuffer = BmpGetBits(offscreenBitmap);
224 WinSetActiveWindow(WinGetDisplayWindow());
225
226 UG_Init(&uguiStruct, uguiDrawPixel, SCREEN_WIDTH, SCREEN_HEIGHT);
227 UG_FontSelect(&SELECTED_FONT);
228 UG_SetBackcolor(C_WHITE);
229 UG_SetForecolor(C_BLACK);
230 UG_ConsoleSetBackcolor(C_WHITE);
231 UG_ConsoleSetForecolor(C_BLACK);
232 UG_FillScreen(C_WHITE);
233
234 /*setup subprogram enviroment*/
235 palmButtons = 0x0000;
236 palmButtonsLastFrame = 0x0000;
237 FtrGet(sysFtrCreator, sysFtrNumOEMDeviceID, &deviceId);
238 isM515 = deviceId == (uint32_t)'lith';/*"lith" is the Palm m515 device code, likely because it is one of the first with a lithium ion battery*/
239 isT3 = deviceId == (uint32_t)'Arz1';
240 skipFrameDelay = false;
241 subprogramIndex = 0;
242 subprogramArgsSet = false;
243 lastSubprogramReturnValue = makeVar(LENGTH_0, TYPE_NULL, 0);
244 subprogramArgs = makeVar(LENGTH_0, TYPE_NULL, 0);
245 currentSubprogram = functionPicker;
246 parentSubprograms[0] = functionPicker;
247
248 /*make function list, needs to be after setting isM515 and unsafeMode*/
249 resetFunctionViewer();
250
251 return true;
252 }
253
testerExit(void)254 static void testerExit(void){
255 MemPtrFree(sharedDataBuffer);
256 }
257
testerFrameLoop(void)258 static void testerFrameLoop(void){
259 static uint32_t lastResetTime = 0;
260 EventType event;
261
262 palmButtons = KeyCurrentState();
263
264 /*allow exiting the app normally and prevent filling up the event loop*/
265 do{
266 EvtGetEvent(&event, 1);
267 SysHandleEvent(&event);
268 if(event.eType == appStopEvent){
269 applicationRunning = false;
270 break;
271 }
272 }
273 while(event.eType != nilEvent);
274
275 /*disable auto off timer*/
276 if(TimGetSeconds() - lastResetTime > 50){
277 EvtResetAutoOffTimer();
278 lastResetTime = TimGetSeconds();
279 }
280
281 lastSubprogramReturnValue = currentSubprogram();
282
283 WinDrawBitmap(offscreenBitmap, 0, 0);
284
285 palmButtonsLastFrame = palmButtons;
286
287 if(!skipFrameDelay)
288 SysTaskDelay(4);/*30 fps*/
289 skipFrameDelay = false;
290 }
291
PilotMain(UInt16 cmd,MemPtr cmdBPB,UInt16 launchFlags)292 UInt32 PilotMain(UInt16 cmd, MemPtr cmdBPB, UInt16 launchFlags){
293 if(cmd == sysAppLaunchCmdNormalLaunch){
294 Boolean initSuccess = testerInit();
295
296 if(!initSuccess)
297 return 0;
298
299 applicationRunning = true;
300
301 while(applicationRunning)
302 testerFrameLoop();
303
304 testerExit();
305 }
306 else if(cmd == sysAppLaunchCmdSystemReset){
307 /*eventualy boot time tests may go here*/
308 }
309
310 return 0;
311 }
312