1 // implementation of the minimal C SDK for KhiCAS
2 int (*shutdown)()=0;
3
4 short shutdown_state=0;
5 short exam_mode=0;
6 unsigned exam_start=0; // RTC start
7 int exam_duration=0;
8 // <0: indicative duration, ==0 time displayed during exam, >0 end exam_mode after
9 const int exam_bg1=0x4321,exam_bg2=0x1234;
exam_bg()10 int exam_bg(){
11 return exam_mode?(exam_duration>0?exam_bg1:exam_bg2):0x0;
12 }
13
14 #ifdef NSPIRE_NEWLIB
15 // NB changes for the nspire cx ii
16 // on_key_pressed() should be modified (returns always true)
17 // https://hackspire.org/index.php?title=Memory-mapped_I/O_ports_on_CX_II#90140000_-_Power_management
18 // cx ii power management 0x90140000,
19 // cx 900B0018 (R/W), 900B0020 (?)
20 // cx ii 90140050 (R/W): Disable bus access to peripherals. Reads will just return the last word read from anywhere in the address range, and writes will be ignored.
21 // cx 900F0020 (R/W): LCD contrast/backlight. Valid range for contrast: 0x11a to 0x1ce; normal value is 0x174. However, it can range from 0x100 (backlight off) to about 0x1d0 (about max brightness).
22 // -> cx ii The OS controls the LCD backlight by writing to 90130018.
23 #include "os.h" // Ndless/ndless-sdk/include/os.h
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <dirent.h>
27 #include <ngc.h>
28 #include "k_defs.h"
29
30
c_rgb565to888(int c)31 int c_rgb565to888(int c){
32 c &= 0xffff;
33 int r=(c>>11)&0x1f,g=(c>>5)&0x3f,b=c&0x1f;
34 return (r<<19)|(g<<10)|(b<<3);
35 }
36
37 const int nspire_statusarea=18;
38 bool nspireemu=false;
39
waitforvblank()40 bool waitforvblank(){
41 }
42
back_key_pressed()43 bool back_key_pressed(){
44 return isKeyPressed(KEY_NSPIRE_DEL);
45 }
46 // next 3 functions may be void if not inside a window class hierarchy
os_show_graph()47 void os_show_graph(){} // show graph inside Python shell (Numworks), not used
os_hide_graph()48 void os_hide_graph(){} // hide graph, not used anymore
os_redraw()49 void os_redraw(){} // force redraw of window class hierarchy
50
os_set_angle_unit(int mode)51 bool os_set_angle_unit(int mode){
52 return false;
53 }
54
os_get_angle_unit()55 int os_get_angle_unit(){
56 return 0;
57 }
58
millis()59 double millis(){
60 unsigned NSPIRE_RTC_ADDR=0x90090000;
61 unsigned t1= * (volatile unsigned *) NSPIRE_RTC_ADDR;
62 return 1000.0*t1;
63 }
64
get_hms(int * h,int * m,int * s)65 void get_hms(int *h,int *m,int *s){
66 unsigned NSPIRE_RTC_ADDR=0x90090000;
67 unsigned t1= * (volatile unsigned *) NSPIRE_RTC_ADDR;
68 if (exam_mode){
69 unsigned t=t1-exam_start;
70 if (exam_duration>0 && t>exam_duration){
71 ;//set_exam_mode(0);
72 }
73 else {
74 if (exam_duration>0)
75 t1=exam_duration-t;
76 else {
77 if (exam_duration<0 && t<-exam_duration)
78 t1=-exam_duration-t;
79 }
80 }
81 }
82 unsigned d=t1/86400;
83 *s=t1%86400;
84 *h=*s/3600;
85 *m=(*s-3600* *h)/60;
86 *s%=60;
87 }
88
os_wait_1ms(int ms)89 void os_wait_1ms(int ms){
90 msleep(ms);
91 }
92
file_exists(const char * filename)93 bool file_exists(const char * filename){
94 if (access(filename,R_OK))
95 return false;
96 }
97
erase_file(const char * filename)98 bool erase_file(const char * filename){
99 return remove(filename)==0;
100 }
101
102 char nspire_filebuf[NSPIRE_FILEBUFFER];
103
read_file(const char * filename)104 const char * read_file(const char * filename){
105 if (exam_mode &&
106 (strcmp(filename,"session.xw")!=0 &&
107 strcmp(filename,"session.xw.tns")!=0 &&
108 strcmp(filename,"session.py")!=0 &&
109 strcmp(filename,"session.py.tns")!=0
110 )
111 )
112 return 0;
113 FILE * f = fopen(filename,"r");
114 if (!f) return 0;
115 fseek(f,0L,SEEK_END);
116 unsigned s = ftell(f);
117 fseek(f,0L,SEEK_SET);
118 if (s>NSPIRE_FILEBUFFER-1){
119 fclose(f);
120 return 0;
121 }
122 for (int i=0;i<s;++i){
123 if (feof(f))
124 break;
125 nspire_filebuf[i]=fgetc(f);
126 }
127 nspire_filebuf[s]=0;
128 fclose(f);
129 return nspire_filebuf;
130 }
131
write_file(const char * filename,const char * s,size_t len)132 bool write_file(const char * filename,const char * s,size_t len){
133 if (exam_mode &&
134 (strcmp(filename,"session.xw")!=0 &&
135 strcmp(filename,"session.xw.tns")!=0 &&
136 strcmp(filename,"session.py")!=0 &&
137 strcmp(filename,"session.py.tns")!=0
138 )
139 )
140 return false;
141 FILE * f=fopen(filename,"w");
142 if (!f) return false;
143 if (!len) len=strlen(s);
144 for (int i=0;i<len;++i)
145 fputc(s[i],f);
146 fclose(f);
147 return true;
148 }
149
150 #define FILENAME_MAXRECORDS 64
151 char os_filenames[32][FILENAME_MAXRECORDS];
os_file_browser(const char ** filenames,int maxrecords,const char * extension)152 int os_file_browser(const char ** filenames,int maxrecords,const char * extension){
153 DIR *dp;
154 struct dirent *ep;
155 if (maxrecords>FILENAME_MAXRECORDS-1)
156 maxrecords=FILENAME_MAXRECORDS-1;
157 dp = opendir (".");
158 if (dp == NULL){
159 filenames[0]=0;
160 return 0;
161 }
162 int cur=0;
163 while ( (ep = readdir (dp)) && cur<maxrecords){
164 const char * s_=ep->d_name,*ext=0;
165 int l=strlen(s_),j;
166 char s[l+1];
167 strcpy(s,s_);
168 for (j=l-1;j>0;--j){
169 if (s[j]=='.'){
170 ext=s+j+1;
171 break;
172 }
173 }
174 if (ext && strcmp(ext,"tns")==0){
175 s[j]=0;
176 for (;j>0;--j){
177 if (s[j]=='.'){
178 ext=s+j+1;
179 break;
180 }
181 }
182 }
183 if (ext && strcmp(ext,extension)==0){
184 if (exam_mode &&
185 (strcmp(s_,"session.xw")!=0 &&
186 strcmp(s_,"session.xw.tns")!=0 &&
187 strcmp(s_,"session.py")!=0 &&
188 strcmp(s_,"session.py.tns")!=0
189 )
190 )
191 continue;
192 strcpy(os_filenames[cur],s_);
193 filenames[cur]=os_filenames[cur];
194 ++cur;
195 }
196 }
197 closedir (dp);
198 // qsort would be faster for large n, but here n<FILENAME_MAXRECORDS
199 for (;;){
200 bool finished=true;
201 for (int i=1;i<cur;++i){
202 if (strcmp(filenames[i-1],filenames[i])>0){
203 finished=false;
204 const char * tmp=filenames[i-1];
205 filenames[i-1]=filenames[i];
206 filenames[i]=tmp;
207 }
208 }
209 if (finished)
210 break;
211 }
212 filenames[cur]=NULL;
213 return cur;
214 }
215
216 Gc nspire_gc=0;
217
get_gc()218 Gc * get_gc(){
219 if (!nspire_gc){
220 nspire_gc=gui_gc_global_GC();
221 gui_gc_setRegion(nspire_gc, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
222 gui_gc_begin(nspire_gc);
223 }
224 return &nspire_gc;
225 }
226
os_set_pixel(int x,int y,int c)227 void os_set_pixel(int x,int y,int c){
228 get_gc();
229 gui_gc_setColor(nspire_gc,c_rgb565to888(c));
230 gui_gc_drawRect(nspire_gc,x,y+nspire_statusarea,1,1);
231 }
232
os_fill_rect(int x,int y,int w,int h,int c)233 void os_fill_rect(int x,int y,int w,int h,int c){
234 get_gc();
235 gui_gc_setColor(nspire_gc,c_rgb565to888(c));
236 gui_gc_fillRect(nspire_gc,x,y+nspire_statusarea,w,h);
237 }
238
os_get_pixel(int x,int y)239 int os_get_pixel(int x,int y){
240 if (x<0 || x>=SCREEN_WIDTH || y<0 || y>=SCREEN_HEIGHT)
241 return -1;
242 #if 1
243 get_gc();
244 char ** off_buff = ((((char *****)nspire_gc)[9])[0])[0x8];
245 int res = *(unsigned short *) (off_buff[y+nspire_statusarea] + 2*x);
246 return res;
247 #else
248 unsigned short * addr=*(unsigned short **) 0xC0000010;
249 int r=addr[(y+nspire_statusarea)*SCREEN_WIDTH+x];
250 return r;
251 #endif
252 }
253
nspire_draw_string(int x,int y,int c,int bg,int f,const char * s,bool fake)254 int nspire_draw_string(int x,int y,int c,int bg,int f,const char * s,bool fake){
255 // void ascii2utf16(void *buf, const char *str, int max_size): converts the UTF-8 string str to the UTF-16 string buf of size max_size.
256 int l=strlen(s);
257 char utf16[2*l+2];
258 ascii2utf16(utf16,s,l);
259 utf16[2*l]=0;
260 utf16[2*l+1]=0;
261 get_gc();
262 gui_gc_setFont(nspire_gc,f);
263 int dx=gui_gc_getStringWidth(nspire_gc, f, utf16, 0, l) ;
264 if (fake)
265 return x+dx;
266 int dy=17;
267 if (f==Regular9)
268 dy=13;
269 if (f==Regular11)
270 dy=16;
271 gui_gc_setColor(nspire_gc,c_rgb565to888(bg));
272 gui_gc_fillRect(nspire_gc,x,y,dx,dy);
273 gui_gc_setColor(nspire_gc,c_rgb565to888(c));
274 //gui_gc_setPen(nspire_gc, GC_PS_MEDIUM, GC_PM_SMOOTH);
275 gui_gc_drawString(nspire_gc, utf16, x, y-1, GC_SM_NORMAL | GC_SM_TOP); // normal mode
276 return x+dx;
277 }
278
os_draw_string(int x,int y,int c,int bg,const char * s,bool fake)279 int os_draw_string(int x,int y,int c,int bg,const char * s,bool fake){
280 get_gc();
281 gui_gc_clipRect(nspire_gc,0,nspire_statusarea,SCREEN_WIDTH,SCREEN_HEIGHT-nspire_statusarea,0);
282 int i=nspire_draw_string(x,y+nspire_statusarea,c,bg,Regular12,s,fake);
283 gui_gc_clipRect(nspire_gc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,GC_CRO_RESET);
284 return i;
285 }
os_draw_string_small(int x,int y,int c,int bg,const char * s,bool fake)286 int os_draw_string_small(int x,int y,int c,int bg,const char * s,bool fake){
287 get_gc();
288 gui_gc_clipRect(nspire_gc,0,nspire_statusarea,SCREEN_WIDTH,SCREEN_HEIGHT-nspire_statusarea,GC_CRO_SET);
289 int i=nspire_draw_string(x,y+nspire_statusarea,c,bg,Regular9,s,fake);
290 gui_gc_clipRect(nspire_gc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,GC_CRO_RESET);
291 return i;
292 }
293
os_draw_string_medium(int x,int y,int c,int bg,const char * s,bool fake)294 int os_draw_string_medium(int x,int y,int c,int bg,const char * s,bool fake){
295 get_gc();
296 gui_gc_clipRect(nspire_gc,0,nspire_statusarea,SCREEN_WIDTH,SCREEN_HEIGHT-nspire_statusarea,GC_CRO_SET);
297 int i=nspire_draw_string(x,y+nspire_statusarea,c,bg,Regular11,s,fake);
298 gui_gc_clipRect(nspire_gc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,GC_CRO_RESET);
299 return i;
300 }
301
statuslinemsg(const char * msg)302 void statuslinemsg(const char * msg){
303 get_gc();
304 int bg=exam_bg();
305 gui_gc_setColor(nspire_gc,c_rgb565to888(bg));
306 gui_gc_fillRect(nspire_gc,0,0,SCREEN_WIDTH,nspire_statusarea);
307 nspire_draw_string(0,0,0xffff,bg,Regular9,msg,false);
308 }
309
display_time()310 void display_time(){
311 int h,m,s;
312 get_hms(&h,&m,&s);
313 char msg[10];
314 msg[0]=' ';
315 msg[1]='0'+(h/10);
316 msg[2]='0'+(h%10);
317 msg[3]= 'h';
318 msg[4]= ('0'+(m/10));
319 msg[5]= ('0'+(m%10));
320 msg[6]=0;
321 //msg[6]= 'm';
322 //msg[7] = ('0'+(s/10));
323 //msg[8] = ('0'+(s%10));
324 //msg[9]=0;
325 int bg=exam_bg();
326 gui_gc_setColor(nspire_gc,c_rgb565to888(bg));
327 gui_gc_fillRect(nspire_gc,270,0,SCREEN_WIDTH-270,nspire_statusarea);
328 nspire_draw_string(270,0,0xffff,bg,Regular9,msg,false);
329 }
330
sync_screen()331 void sync_screen(){
332 get_gc();
333 //gui_gc_finish(nspire_gc);
334 gui_gc_blit_to_screen(nspire_gc);
335 msleep(10);
336 //nspire_gc=0;
337 // gui_gc_begin(nspire_gc);
338 }
339
340 // Nspire peripheral reset :
341 // https://github.com/nDroidProject/nDroid-bootloader/blob/master/kernel.c
342 // https://hackspire.org/index.php?title=Memory-mapped_I/O_ports_on_CX#CC000000_-_SHA-256_hash_generator
343 // hardware ports
344 // https://hackspire.org/index.php?title=Memory-mapped_I/O_ports_on_CX
345
346 bool nspire_shift=false;
347 bool nspire_ctrl=false;
348 bool nspire_select=false;
statusline(int mode)349 void statusline(int mode){
350 char *msg=0;
351 if (nspire_ctrl){
352 if (nspire_shift)
353 msg="shift ctrl";
354 else
355 msg=" ctrl";
356 }
357 else {
358 if (nspire_shift)
359 msg="shift";
360 else
361 msg="";
362 }
363 int bg=exam_bg();
364 gui_gc_setColor(nspire_gc,c_rgb565to888(bg));
365 gui_gc_fillRect(nspire_gc,210,0,SCREEN_WIDTH-210,nspire_statusarea);
366 nspire_draw_string(220,0,0xffff,bg,Regular9,msg,false);
367 if (nspireemu)
368 nspire_draw_string(210,0,0xffff,bg,Regular9,"e",false);
369 display_time();
370 if (mode==0)
371 return;
372 sync_screen();
373 }
374
375
376 #define SHIFTCTRL(x, y, z) (nspire_ctrl ? (z) : nspire_shift ? (y) : (x))
377 #define SHIFT(x, y) SHIFTCTRL(x, y, x)
378 #define CTRL(x, y) SHIFTCTRL(x, x, y)
379 #define NORMAL(x) SHIFTCTRL(x, x, x)
380
ascii_get(int * adaptive_cursor_state)381 int ascii_get(int* adaptive_cursor_state){
382 if (isKeyPressed(KEY_NSPIRE_CTRL)){
383 nspire_ctrl=!nspire_ctrl;
384 statusline(0);
385 sync_screen();
386 return -2;
387 }
388 if (isKeyPressed(KEY_NSPIRE_SHIFT)){
389 nspire_shift=!nspire_shift;
390 statusline(0);
391 sync_screen();
392 return -1;
393 }
394 *adaptive_cursor_state = SHIFTCTRL(0, 1, 4);
395 if (isKeyPressed(KEY_NSPIRE_LEFT)|| isKeyPressed(KEY_NSPIRE_LEFTUP) || isKeyPressed(KEY_NSPIRE_DOWNLEFT)) return SHIFTCTRL(KEY_CTRL_LEFT,KEY_SHIFT_LEFT,KEY_LEFT_CTRL);
396 if (isKeyPressed(KEY_NSPIRE_RIGHT)|| isKeyPressed(KEY_NSPIRE_UPRIGHT) || isKeyPressed(KEY_NSPIRE_RIGHTDOWN)) return SHIFTCTRL(KEY_CTRL_RIGHT,KEY_SHIFT_RIGHT,KEY_RIGHT_CTRL);
397 if (isKeyPressed(KEY_NSPIRE_UP)) return SHIFTCTRL(KEY_CTRL_UP,KEY_CTRL_PAGEUP,KEY_UP_CTRL);
398 if (isKeyPressed(KEY_NSPIRE_DOWN)) return SHIFTCTRL(KEY_CTRL_DOWN,KEY_CTRL_PAGEDOWN,KEY_DOWN_CTRL);
399
400 if (isKeyPressed(KEY_NSPIRE_ESC)) return KEY_CTRL_EXIT ;
401 if (isKeyPressed(KEY_NSPIRE_HOME)) return KEY_CTRL_MENU ;
402 if (isKeyPressed(KEY_NSPIRE_MENU)) return KEY_CTRL_MENU ;
403
404 // Characters
405 if (isKeyPressed(KEY_NSPIRE_A)) return SHIFTCTRL('a','A',KEY_CTRL_A);
406 if (isKeyPressed(KEY_NSPIRE_B)) return SHIFTCTRL('b','B',KEY_BOOK);
407 if (isKeyPressed(KEY_NSPIRE_C)) return SHIFTCTRL('c','C',KEY_CTRL_CLIP);
408 if (isKeyPressed(KEY_NSPIRE_D)) return SHIFTCTRL('d','D',KEY_CTRL_D);
409 if (isKeyPressed(KEY_NSPIRE_E)) return SHIFTCTRL('e','E',KEY_CTRL_F10);
410 if (isKeyPressed(KEY_NSPIRE_F)) return SHIFTCTRL('f','F',KEY_CTRL_F11);
411 if (isKeyPressed(KEY_NSPIRE_G)) return SHIFTCTRL('g','G',KEY_CTRL_F12);
412 if (isKeyPressed(KEY_NSPIRE_H)) return SHIFTCTRL('h','H',KEY_CTRL_F13);
413 if (isKeyPressed(KEY_NSPIRE_I)) return SHIFTCTRL('i','I',KEY_CTRL_F14);
414 if (isKeyPressed(KEY_NSPIRE_J)) return SHIFT('j','J');
415 if (isKeyPressed(KEY_NSPIRE_K)) return SHIFTCTRL('k','K',KEY_CTRL_AC);
416 if (isKeyPressed(KEY_NSPIRE_L)) return SHIFTCTRL('l','L',KEY_CTRL_F14);
417 if (isKeyPressed(KEY_NSPIRE_M)) return SHIFTCTRL('m','M',KEY_CTRL_CATALOG);
418 if (isKeyPressed(KEY_NSPIRE_N)) return SHIFTCTRL('n','N',KEY_CTRL_N);
419 if (isKeyPressed(KEY_NSPIRE_O)) return SHIFTCTRL('o','O',KEY_SHIFT_OPTN);
420 if (isKeyPressed(KEY_NSPIRE_P)) return SHIFTCTRL('p','P',KEY_CTRL_PRGM);
421 if (isKeyPressed(KEY_NSPIRE_Q)) return SHIFT('q','Q');
422 if (isKeyPressed(KEY_NSPIRE_R)) return SHIFTCTRL('r','R',KEY_CTRL_R);
423 if (isKeyPressed(KEY_NSPIRE_S)) return SHIFTCTRL('s','S',KEY_CTRL_S);
424 if (isKeyPressed(KEY_NSPIRE_T)) return SHIFTCTRL('t','T',KEY_CTRL_T);
425 if (isKeyPressed(KEY_NSPIRE_U)) return SHIFTCTRL('u','U',KEY_CTRL_F13);
426 if (isKeyPressed(KEY_NSPIRE_V)) return SHIFTCTRL('v','V',KEY_CTRL_PASTE);
427 if (isKeyPressed(KEY_NSPIRE_W)) return SHIFT('w','W');
428 if (isKeyPressed(KEY_NSPIRE_X)) return SHIFTCTRL('x','X',KEY_CTRL_CUT);
429 if (isKeyPressed(KEY_NSPIRE_Y)) return SHIFT('y','Y');
430 if (isKeyPressed(KEY_NSPIRE_Z)) return SHIFTCTRL('z','Z',KEY_CTRL_UNDO);
431
432 // Numbers
433 if (nspireemu){ // for firebird, redefine ctrl
434 if (isKeyPressed(KEY_NSPIRE_0)) return SHIFTCTRL('0',KEY_CTRL_F10,')');
435 if (isKeyPressed(KEY_NSPIRE_1)) return SHIFTCTRL('1',KEY_CTRL_F1,'!');
436 if (isKeyPressed(KEY_NSPIRE_2)) return SHIFTCTRL('2',KEY_CTRL_F2,'@');
437 if (isKeyPressed(KEY_NSPIRE_3)) return SHIFTCTRL('3',KEY_CTRL_F3,'#');
438 if (isKeyPressed(KEY_NSPIRE_4)) return SHIFTCTRL('4',KEY_CTRL_F4,'$');
439 if (isKeyPressed(KEY_NSPIRE_5)) return SHIFTCTRL('5',KEY_CTRL_F5,'%');
440 if (isKeyPressed(KEY_NSPIRE_6)) return SHIFTCTRL('6',KEY_CTRL_F6,'^');
441 if (isKeyPressed(KEY_NSPIRE_7)) return SHIFTCTRL('7',KEY_CTRL_F7,'&');
442 if (isKeyPressed(KEY_NSPIRE_8)) return SHIFTCTRL('8',KEY_CTRL_F8,'*');
443 if (isKeyPressed(KEY_NSPIRE_9)) return SHIFTCTRL('9',KEY_CTRL_F9,'(');
444 }
445 else {
446 if (isKeyPressed(KEY_NSPIRE_0)) return SHIFTCTRL('0',KEY_CTRL_F10,KEY_CTRL_F10);
447 if (isKeyPressed(KEY_NSPIRE_1)) return SHIFTCTRL('1',KEY_CTRL_F1,KEY_CTRL_F1);
448 if (isKeyPressed(KEY_NSPIRE_2)) return SHIFTCTRL('2',KEY_CTRL_F2,KEY_CTRL_F2);
449 if (isKeyPressed(KEY_NSPIRE_3)) return SHIFTCTRL('3',KEY_CTRL_F3,KEY_CTRL_F3);
450 if (isKeyPressed(KEY_NSPIRE_4)) return SHIFTCTRL('4',KEY_CTRL_F4,KEY_CTRL_F4);
451 if (isKeyPressed(KEY_NSPIRE_5)) return SHIFTCTRL('5',KEY_CTRL_F5,KEY_CTRL_F5);
452 if (isKeyPressed(KEY_NSPIRE_6)) return SHIFTCTRL('6',KEY_CTRL_F6,KEY_CTRL_F6);
453 if (isKeyPressed(KEY_NSPIRE_7)) return SHIFTCTRL('7',KEY_CTRL_F7,KEY_CTRL_F7);
454 if (isKeyPressed(KEY_NSPIRE_8)) return SHIFTCTRL('8',KEY_CTRL_F8,KEY_CTRL_F8);
455 if (isKeyPressed(KEY_NSPIRE_9)) return SHIFTCTRL('9',KEY_CTRL_F9,KEY_CTRL_F9);
456 }
457
458 // Symbols
459 if (isKeyPressed(KEY_NSPIRE_FRAC)) return SHIFTCTRL(KEY_EQW_TEMPLATE,KEY_AFFECT,KEY_AFFECT);
460 if (isKeyPressed(KEY_NSPIRE_SQU)) return CTRL(KEY_CHAR_SQUARE,KEY_CHAR_ROOT);
461 if (isKeyPressed(KEY_NSPIRE_TENX)) return CTRL(KEY_CHAR_EXPN10,KEY_CHAR_LOG);
462 if (isKeyPressed(KEY_NSPIRE_eEXP)) return CTRL(KEY_CHAR_EXPN,KEY_CHAR_LN);
463 if (isKeyPressed(KEY_NSPIRE_COMMA)) return SHIFTCTRL(',',';',':');
464 if (isKeyPressed(KEY_NSPIRE_PERIOD)) return SHIFTCTRL('.',':',KEY_CTRL_F11);
465 if (isKeyPressed(KEY_NSPIRE_COLON)) return NORMAL(':');
466 if (isKeyPressed(KEY_NSPIRE_LP)) return SHIFTCTRL('(',']','[');
467 if (isKeyPressed(KEY_NSPIRE_RP)) return SHIFTCTRL(')','}','{');
468 if (isKeyPressed(KEY_NSPIRE_SPACE)) return SHIFT(' ','_');
469 if (isKeyPressed(KEY_NSPIRE_DIVIDE))
470 return SHIFTCTRL('/','%','\\');
471 if (isKeyPressed(KEY_NSPIRE_MULTIPLY)) return SHIFTCTRL('*','\'','\"');
472 if (isKeyPressed(KEY_NSPIRE_MINUS)) return SHIFTCTRL('-','<', '_');
473 if (isKeyPressed(KEY_NSPIRE_NEGATIVE)) return SHIFTCTRL('-','_',KEY_CHAR_ANS);
474 if (isKeyPressed(KEY_NSPIRE_PLUS)) return SHIFTCTRL('+', '>','>');
475 if (isKeyPressed(KEY_NSPIRE_EQU)) return SHIFTCTRL('=', '|',KEY_CHAR_STORE);
476 if (isKeyPressed(KEY_NSPIRE_LTHAN)) return NORMAL('<');
477 if (isKeyPressed(KEY_NSPIRE_GTHAN)) return NORMAL('>');
478 if (isKeyPressed(KEY_NSPIRE_QUOTE)) return NORMAL('\"');
479 if (isKeyPressed(KEY_NSPIRE_APOSTROPHE)) return NORMAL('\'');
480 if (isKeyPressed(KEY_NSPIRE_QUES)) return SHIFTCTRL('?','|','!');
481 if (isKeyPressed(KEY_NSPIRE_QUESEXCL)) return SHIFTCTRL('?','|','!');
482 if (isKeyPressed(KEY_NSPIRE_BAR)) return NORMAL('|');
483 if (isKeyPressed(KEY_NSPIRE_EXP)) return SHIFT('^',KEY_CHAR_RECIP);
484 if (isKeyPressed(KEY_NSPIRE_EE)) return SHIFTCTRL('&','%', '@');
485 if (isKeyPressed(KEY_NSPIRE_PI)) return KEY_CHAR_PI;
486 if (isKeyPressed(KEY_NSPIRE_FLAG)) return SHIFTCTRL(';',':',KEY_CHAR_IMGNRY);
487 if (isKeyPressed(KEY_NSPIRE_ENTER)) return SHIFTCTRL(KEY_CTRL_OK,'~',KEY_CTRL_EXE);
488 if (isKeyPressed(KEY_NSPIRE_TRIG)) return SHIFTCTRL(KEY_CHAR_SIN,KEY_CHAR_COS,KEY_CHAR_TAN);
489
490 // Special chars
491 if (isKeyPressed(KEY_NSPIRE_SCRATCHPAD)) return SHIFTCTRL(KEY_CTRL_SETUP,KEY_LOAD,KEY_SAVE);
492 if (isKeyPressed(KEY_NSPIRE_VAR)) return CTRL(KEY_CTRL_VARS,KEY_CHAR_STORE);
493 if (isKeyPressed(KEY_NSPIRE_DOC)) return KEY_CTRL_CATALOG;
494 if (isKeyPressed(KEY_NSPIRE_CAT)) return KEY_BOOK;
495 if (isKeyPressed(KEY_NSPIRE_DEL)) return SHIFTCTRL(KEY_CTRL_DEL,KEY_CTRL_DEL,KEY_CTRL_AC);
496 if (isKeyPressed(KEY_NSPIRE_RET)) return KEY_CTRL_EXE;
497 if (isKeyPressed(KEY_NSPIRE_TAB)) return '\t';
498
499 return 0;
500 }
501
iskeydown(int key)502 bool iskeydown(int key){
503 t_key t=KEY_NSPIRE_SPACE;
504 switch (key){
505 case 0:
506 t=KEY_NSPIRE_LEFT;
507 break;
508 case 1:
509 t=KEY_NSPIRE_UP;
510 break;
511 case 2:
512 t=KEY_NSPIRE_DOWN;
513 break;
514 case 3:
515 t=KEY_NSPIRE_RIGHT;
516 break;
517 case 4:
518 t=KEY_NSPIRE_ENTER;
519 break;
520 case 5:
521 t=KEY_NSPIRE_ESC;
522 break;
523 case 6:
524 t=KEY_NSPIRE_HOME;
525 break;
526 case 7:
527 t=KEY_NSPIRE_MENU;
528 break;
529 case 12:
530 t=KEY_NSPIRE_SHIFT;
531 break;
532 case 13:
533 t=KEY_NSPIRE_CTRL;
534 break;
535 case 14:
536 t=KEY_NSPIRE_SCRATCHPAD;
537 break;
538 case 15:
539 t=KEY_NSPIRE_VAR;
540 break;
541 case 16:
542 t=KEY_NSPIRE_DOC;
543 break;
544 case 17:
545 t=KEY_NSPIRE_DEL;
546 break;
547 case 18:
548 t=KEY_NSPIRE_eEXP;
549 break;
550 case 19:
551 t=KEY_NSPIRE_EQU;
552 break;
553 case 20:
554 t=KEY_NSPIRE_TENX;
555 break;
556 case 21:
557 t=KEY_NSPIRE_I;
558 break;
559 case 22:
560 t=KEY_NSPIRE_COMMA;
561 break;
562 case 23:
563 t=KEY_NSPIRE_EXP;
564 break;
565 case 24:
566 t=KEY_NSPIRE_TRIG;
567 break;
568 case 25:
569 t=KEY_NSPIRE_C;
570 break;
571 case 26:
572 t=KEY_NSPIRE_T;
573 break;
574 case 27:
575 t=KEY_NSPIRE_PI;
576 break;
577 case 28:
578 t=KEY_NSPIRE_S;
579 break;
580 case 29:
581 t=KEY_NSPIRE_SQU;
582 break;
583 case 30:
584 t=KEY_NSPIRE_7;
585 break;
586 case 31:
587 t=KEY_NSPIRE_8;
588 break;
589 case 32:
590 t=KEY_NSPIRE_9;
591 break;
592 case 33:
593 t=KEY_NSPIRE_LP;
594 break;
595 case 34:
596 t=KEY_NSPIRE_RP;
597 break;
598 case 36:
599 t=KEY_NSPIRE_4;
600 break;
601 case 37:
602 t=KEY_NSPIRE_5;
603 break;
604 case 38:
605 t=KEY_NSPIRE_6;
606 break;
607 case 39:
608 t=KEY_NSPIRE_MULTIPLY;
609 break;
610 case 40:
611 t=KEY_NSPIRE_DIVIDE;
612 break;
613 case 42:
614 t=KEY_NSPIRE_1;
615 break;
616 case 43:
617 t=KEY_NSPIRE_2;
618 break;
619 case 44:
620 t=KEY_NSPIRE_3;
621 break;
622 case 45:
623 t=KEY_NSPIRE_PLUS;
624 break;
625 case 46:
626 t=KEY_NSPIRE_MINUS;
627 break;
628 case 48:
629 t=KEY_NSPIRE_0;
630 break;
631 case 49:
632 t=KEY_NSPIRE_PERIOD;
633 break;
634 case 50:
635 t=KEY_NSPIRE_EE;
636 break;
637 case 51:
638 t=KEY_NSPIRE_NEGATIVE;
639 break;
640 case 52:
641 t=KEY_NSPIRE_RET;
642 break;
643 }
644 return isKeyPressed(t);
645 }
646
647 // ? see also ndless-sdk/thirdparty/nspire-io/arch-nspire/nspire.c nio_ascii_get
getkey(int allow_suspend)648 int getkey(int allow_suspend){
649 sync_screen();
650 if (shutdown_state)
651 return KEY_SHUTDOWN;
652 int lastkey=-1;
653 unsigned NSPIRE_RTC_ADDR=0x90090000;
654 static unsigned lastt=0;
655 for (;;){
656 unsigned t1= * (volatile unsigned *) NSPIRE_RTC_ADDR;
657 if (lastt==0)
658 lastt=t1;
659 if (t1-lastt>10){
660 display_time();
661 sync_screen();
662 }
663 bool autosuspend=(t1-lastt>=100);
664 if (allow_suspend && (autosuspend || (nspire_ctrl && on_key_pressed()))){
665 nspire_ctrl=nspire_shift=false;
666 while (!autosuspend && on_key_pressed())
667 msleep(10);
668 // somewhat OFF by setting LCD to 0
669 unsigned NSPIRE_CONTRAST_ADDR=0x900f0020;
670 unsigned oldval=*(volatile unsigned *)NSPIRE_CONTRAST_ADDR;
671 *(volatile unsigned *)NSPIRE_CONTRAST_ADDR=0x100;
672 static volatile uint32_t *lcd_controller = (volatile uint32_t*) 0xC0000000;
673 lcd_controller[6] &= ~(0b1 << 11);
674 msleep(20);
675 lcd_controller[6] &= ~ 0b1;
676 unsigned offtime=* (volatile unsigned *) NSPIRE_RTC_ADDR;
677 for (int n=0;!on_key_pressed();++n){
678 msleep(100);
679 idle();
680 if (!exam_mode && shutdown
681 // && n&0xff==0
682 ){
683 unsigned curtime=* (volatile unsigned *) NSPIRE_RTC_ADDR;
684 if (curtime-offtime>7200){
685 shutdown_state=1;
686 // after 2 hours, leave KhiCAS
687 // that way the OS will really shutdown the calc
688 lcd_controller[6] |= 0b1;
689 msleep(20);
690 lcd_controller[6]|= 0b1 << 11;
691 *(volatile unsigned *)NSPIRE_CONTRAST_ADDR=oldval;
692 statuslinemsg("Press ON to disable KhiCAS auto shutdown");
693 //os_fill_rect(0,0,320,222,0xffff);
694 sync_screen();
695 int m=0,mmax=150;
696 for (;m<mmax;++m){
697 if (on_key_pressed())
698 break;
699 msleep(100);
700 idle();
701 }
702 if (m==mmax){
703 if (shutdown())
704 return KEY_SHUTDOWN;
705 }
706 else {
707 shutdown_state=0;
708 break;
709 }
710 }
711 }
712 }
713 lcd_controller[6] |= 0b1;
714 msleep(20);
715 lcd_controller[6]|= 0b1 << 11;
716 *(volatile unsigned *)NSPIRE_CONTRAST_ADDR=oldval;
717 statusline(0);
718 sync_screen();
719 lastt=* (volatile unsigned *) NSPIRE_RTC_ADDR;
720 continue;
721 }
722 if (!any_key_pressed()){
723 if (nspireemu)
724 msleep(50); // 100?
725 else // real calculator
726 msleep(1);
727 continue;
728 }
729 lastt=t1;
730 int cursor_state=0;
731 int i=0;
732 if (isKeyPressed(KEY_NSPIRE_SHIFT)){
733 while (i==0 && isKeyPressed(KEY_NSPIRE_SHIFT)){
734 if (isKeyPressed(KEY_NSPIRE_LEFT)|| isKeyPressed(KEY_NSPIRE_LEFTUP) || isKeyPressed(KEY_NSPIRE_DOWNLEFT))
735 i=KEY_SELECT_LEFT;
736 if (isKeyPressed(KEY_NSPIRE_RIGHT)|| isKeyPressed(KEY_NSPIRE_UPRIGHT) || isKeyPressed(KEY_NSPIRE_RIGHTDOWN))
737 i=KEY_SELECT_RIGHT;
738 if (isKeyPressed(KEY_NSPIRE_UP))
739 i=KEY_SELECT_UP;
740 if (isKeyPressed(KEY_NSPIRE_DOWN))
741 i=KEY_SELECT_DOWN;
742 }
743 if (i!=0){
744 nspire_select=true;
745 }
746 if (i==0){
747 nspire_shift=!nspire_shift;
748 statusline(0);
749 sync_screen();
750 i=-1;
751 }
752 }
753 else {
754 if (nspire_select){
755 nspire_select=nspire_shift=false;
756 statusline(0);
757 sync_screen();
758 continue;
759 }
760 i=ascii_get(&cursor_state);
761 }
762 if (i<0){
763 wait_no_key_pressed();
764 continue;
765 }
766 if (i==KEY_CTRL_N){
767 nspireemu=!nspireemu;
768 nspire_ctrl=nspire_shift=false;
769 statusline(0);
770 sync_screen();
771 continue;
772 }
773 if ( (i>=KEY_CTRL_LEFT && i<=KEY_CTRL_RIGHT) ||
774 (i>=KEY_UP_CTRL && i<=KEY_RIGHT_CTRL) ||
775 (i>=KEY_SELECT_LEFT && i<=KEY_SELECT_RIGHT) ||
776 i==KEY_CTRL_DEL){
777 int delay=(lastkey==i)?5:40,j;
778 for (j=0;j<delay && any_key_pressed();++j){
779 if (nspireemu)
780 msleep(14);
781 else
782 msleep(1);
783 }
784 if (any_key_pressed())
785 lastkey=i;
786 else
787 lastkey=-1;
788 }
789 else {
790 wait_no_key_pressed();
791 lastkey=-1;
792 }
793 if (nspire_ctrl || nspire_shift){
794 nspire_ctrl=nspire_shift=false;
795 statusline(0);
796 sync_screen();
797 }
798 return i;
799 }
800 // void send_key_event(struct s_ns_event* eventbuf, unsigned short keycode_asciicode, BOOL is_key_up, BOOL unknown): since r721. Simulate a key event
801 }
802
803 // void idle(void)
804 // void msleep(unsigned ms)
805 // cfg_register_fileext(const char *ext, const char *prgm): (since v3.1 r797) associate for Ndless the file extension ext (without leading '.') to the program name prgm. Does nothing if the extension is already registered.
806
GetKey(int * key)807 void GetKey(int * key){
808 *key=getkey(true);
809 }
810
alphawasactive(int * key)811 bool alphawasactive(int * key){
812 if (*key==KEY_DOWN_CTRL){
813 *key=KEY_CTRL_DOWN;
814 return true;
815 }
816 if (*key==KEY_UP_CTRL){
817 *key=KEY_CTRL_UP;
818 return true;
819 }
820 if (*key==KEY_LEFT_CTRL){
821 *key=KEY_CTRL_LEFT;
822 return true;
823 }
824 if (*key==KEY_RIGHT_CTRL){
825 *key=KEY_CTRL_RIGHT;
826 return true;
827 }
828 return false;
829 }
830
isalphaactive()831 bool isalphaactive(){
832 return false;//nspire_ctrl;
833 }
834
lock_alpha()835 void lock_alpha(){
836 //nspire_ctrl=true;
837 }
838
reset_kbd()839 void reset_kbd(){
840 nspire_ctrl=nspire_shift=false;
841 }
842
843 bool on_key_enabled=true;
844
enable_back_interrupt()845 void enable_back_interrupt(){
846 on_key_enabled=true;
847 }
848
disable_back_interrupt()849 void disable_back_interrupt(){
850 on_key_enabled=false;
851 }
852 #else // NSPIRE_NEWLIB
853
set_exam_mode(int i)854 void set_exam_mode(int i){
855 exam_mode=i;
856 }
857 #endif // NSPIRE_NEWLIB
858