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