00001 00006 /* 00007 * The contents of this file are subject to the Mozilla Public License 00008 * Version 1.0 (the "License"); you may not use this file except in 00009 * compliance with the License. You may obtain a copy of the License at 00010 * http://www.mozilla.org/MPL/ 00011 * 00012 * Software distributed under the License is distributed on an "AS IS" 00013 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 00014 * License for the specific language governing rights and limitations 00015 * under the License. 00016 * 00017 * The Original Code is legOS code, released October 17, 1999. 00018 * 00019 * The Initial Developer of the Original Code is Markus L. Noga. 00020 * Portions created by Markus L. Noga are Copyright (C) 1999 00021 * Markus L. Noga. All Rights Reserved. 00022 * 00023 * Contributor(s): Markus L. Noga <markus@noga.de> 00024 * Frank Cremer <frank@demon.holly.nl> 00025 */ 00026 00027 /* 00028 * 2000.05.01 - Paolo Masetti <paolo.masetti@itlug.org> 00029 * 00030 * - Added "CMDirmode" for changing via LNP IR mode 00031 * 00032 * 2001.05.10 - Matt Ahrens <mahrens@acm.org> 00033 * 00034 * - Added free memory and batter life display 00035 * Press "view" repeatedly while no programs are running to see 00036 * 00037 * 2002.4.23 - Ted Hess <thess@kitschensync.net> 00038 * 00039 * - Added Remote key handler 00040 */ 00041 00042 #include <sys/program.h> 00043 00044 #ifdef CONF_PROGRAM 00045 00046 #include <sys/tm.h> 00047 #include <string.h> 00048 #include <semaphore.h> 00049 #include <unistd.h> 00050 #include <stdlib.h> 00051 00052 #include <sys/lnp.h> 00053 #include <sys/lnp-logical.h> 00054 #include <sys/dmotor.h> 00055 #include <sys/dsensor.h> 00056 #include <sys/mm.h> 00057 #include <sys/battery.h> 00058 #include <dsound.h> 00059 #include <remote.h> 00060 00061 #include <conio.h> 00062 00064 // 00065 // Global Variables 00066 // 00068 00069 volatile unsigned cprog; 00070 00072 // 00073 // Internal Variables 00074 // 00076 00077 const unsigned char min_length[]={ 00078 1, // CMDacknowledge 00079 2, // CMDdelete 00080 13, // CMDcreate 00081 8, // CMDoffsets 00082 4, // CMDdata 00083 2, // CMDrun 00084 2, // CMDirmode 00085 2 // CMDsethost 00086 }; 00087 00088 static program_t programs[PROG_MAX]; 00089 00090 static unsigned char* buffer_ptr; 00091 volatile unsigned char packet_len; 00092 volatile unsigned char packet_src; 00093 00094 static sem_t packet_sem; 00095 00096 #if 0 00097 #define debugs(a) { cputs(a); msleep(500); } 00098 #define debugw(a) { cputw(a); msleep(500); } 00099 #else 00100 #define debugs(a) 00101 #define debugw(a) 00102 #endif 00103 00104 // Forward ref 00105 int lrkey_handler(unsigned int etype, unsigned int key); 00106 00108 // 00109 // Functions 00110 // 00112 00114 00115 int program_valid(unsigned nr) { 00116 program_t *prog=programs+nr; 00117 00118 return (nr < PROG_MAX) && 00119 (prog->text_size>0) && 00120 (prog->text_size+prog->data_size==prog->downloaded); 00121 } 00122 00124 static void program_run(unsigned nr) { 00125 if(program_valid(nr)) { 00126 program_t *prog=programs+nr; 00127 00128 // initialize data segments 00129 // 00130 memcpy(prog->data,prog->data_orig,prog->data_size); 00131 memset(prog->bss,0,prog->bss_size); 00132 00133 execi((void*) (((char*)prog->text) 00134 + prog->start ), 00135 0,0,prog->prio,prog->stack_size); 00136 } 00137 } 00138 00140 00142 static void packet_producer(const unsigned char *data, 00143 unsigned char length, 00144 unsigned char src) { 00145 // old packet still unhandled or empty packet? 00146 // 00147 if(packet_len>0 || length==0) 00148 return; 00149 00150 if (buffer_ptr != 0) 00151 return; 00152 00153 buffer_ptr = malloc(length); 00154 memcpy(buffer_ptr,data,length); 00155 packet_len=length; 00156 packet_src=src; 00157 sem_post(&packet_sem); 00158 } 00159 00161 static int packet_consumer(int argc, char *argv[]) { 00162 packet_cmd_t cmd; 00163 unsigned char nr=0; 00164 program_t *prog=programs; // to avoid a silly warning 00165 const static unsigned char acknowledge=CMDacknowledge; 00166 char msg[8]; 00167 00168 while (!shutdown_requested()) { 00169 // wait for new packet 00170 // 00171 packet_len=0; 00172 free(buffer_ptr); 00173 buffer_ptr = 0; 00174 if (sem_wait(&packet_sem) != -1) { 00175 if (buffer_ptr == 0) 00176 continue; 00177 00178 debugw(*(size_t*)buffer_ptr); 00179 00180 // handle trivial errors 00181 // 00182 cmd=buffer_ptr[0]; 00183 if (cmd>=CMDlast || packet_len<min_length[cmd]) 00184 continue; 00185 00186 // handle IR CMDs 00187 if (cmd==CMDirmode) { 00188 if (buffer_ptr[1]==0) { 00189 debugs("nearmodeIR"); 00190 lnp_logical_range(0); 00191 debugs("OK"); 00192 lnp_addressing_write(&acknowledge,1,packet_src,0); 00193 } else { 00194 debugs("farmodeIR"); 00195 lnp_logical_range(1); 00196 debugs("OK"); 00197 lnp_addressing_write(&acknowledge,1,packet_src,0); 00198 } 00199 continue; 00200 } 00201 00202 // Is this a request to change host address 00203 if (cmd == CMDsethost) { 00204 // ACK before we change our address 00205 lnp_addressing_write(&acknowledge,1,packet_src,0); 00206 lnp_set_hostaddr(buffer_ptr[1]); 00207 continue; 00208 } 00209 00210 // Get program number, validate value 00211 if((cmd > CMDacknowledge) && (cmd <= CMDrun)) { 00212 nr = buffer_ptr[1]; 00213 if(nr > PROG_MAX) 00214 continue; 00215 #ifndef CONF_VIS 00216 cputc_hex_0(nr+1); 00217 #endif 00218 } 00219 00220 debugw(nr); 00221 prog = programs+nr; 00222 00223 switch( cmd ) { 00224 case CMDdelete: 00225 debugs("dele"); 00226 00227 if(nb_tasks <= nb_system_tasks) { 00228 if(prog->text) 00229 free(prog->text); 00230 memset(prog,0,sizeof(program_t)); 00231 00232 #ifndef CONF_VIS 00233 if(nr == cprog) 00234 cputc_0('-'); 00235 #endif 00236 debugs("OK"); 00237 00238 lnp_addressing_write(&acknowledge,1,packet_src,0); 00239 } 00240 break; 00241 00242 case CMDcreate: 00243 debugs("crea"); 00244 if(!prog->text) { 00245 memcpy(&(prog->text_size),buffer_ptr+2,11); 00246 00247 if((prog->text=malloc(prog->text_size+ 00248 2*prog->data_size+ 00249 prog->bss_size ))) { 00250 prog->data=prog->text+prog->text_size; 00251 prog->bss=prog->data+prog->data_size; 00252 prog->data_orig=prog->bss +prog->bss_size; 00253 prog->downloaded=0; 00254 00255 debugs("OK"); 00256 00257 cputw(0); 00258 cprog = nr; 00259 00260 msg[0]=CMDacknowledge; 00261 msg[1]=nr; 00262 memcpy(msg+2,prog,6); 00263 lnp_addressing_write(msg,8,packet_src,0); 00264 } else 00265 memset(prog,0,sizeof(program_t)); 00266 } 00267 break; 00268 00269 case CMDdata: 00270 debugs("data"); 00271 if(prog->text && !program_valid(nr)) { 00272 size_t offset=*(size_t*)(buffer_ptr+2); 00273 if(offset<=prog->downloaded) { 00274 if(offset==prog->downloaded) { 00275 memcpy(prog->text+offset,buffer_ptr+4,packet_len-4); 00276 prog->downloaded+=packet_len-4; 00277 00278 if(program_valid(nr)) { 00279 // copy original data segment and we're done. 00280 // 00281 memcpy(prog->data_orig,prog->data,prog->data_size); 00282 cls(); 00283 } else 00284 cputw(prog->downloaded); 00285 debugs("OK"); 00286 } else 00287 debugs("OLD"); 00288 00289 lnp_addressing_write(&acknowledge,1,packet_src,0); 00290 } 00291 } 00292 break; 00293 00294 case CMDrun: 00295 debugs("run"); 00296 if(program_valid(nr)) { 00297 cprog = nr; 00298 program_stop(0); 00299 program_run(nr); 00300 00301 debugs("OK"); 00302 lnp_addressing_write(&acknowledge,1,packet_src,0); 00303 } 00304 break; 00305 00306 default: 00307 debugs("error"); 00308 } 00309 } 00310 } 00311 free(buffer_ptr); 00312 return 0; 00313 } 00314 00316 void program_stop(int flag) { 00317 int count_down = 40; 00318 00319 // Kindly request that all user tasks shutdown 00320 shutdown_tasks(T_USER); 00321 // Wait a bit 00322 while (--count_down && (nb_tasks > nb_system_tasks)) { 00323 if (flag) 00324 cputs("STOP"); 00325 msleep(100); 00326 } 00327 00328 if (nb_tasks > nb_system_tasks) { 00329 // Wait no longer. 00330 if (flag) { 00331 cputs("KILL"); 00332 // display immediately 00333 lcd_refresh(); 00334 } 00335 killall(PRIO_HIGHEST-1); 00336 } 00337 00338 // Reset motors, sensors, sound & LNP as 00339 // programs may have motors running, 00340 // sensors active or handlers set. 00341 // 00342 // Programs that exit on their own 00343 // are assumed to take the necessary 00344 // actions themselves. 00345 // 00346 #ifdef CONF_DSOUND 00347 dsound_stop(); 00348 #endif 00349 #ifdef CONF_DMOTOR 00350 dm_init(); 00351 #endif 00352 #ifdef CONF_DSENSOR 00353 ds_init(); 00354 #endif 00355 lnp_init(); 00356 #ifdef CONF_LR_HANDLER 00357 // Reset remote button handler 00358 lr_init(); 00359 lr_set_handler(lrkey_handler); 00360 #endif 00361 } 00362 00364 int key_handler(int argc, char *argv[]) { 00365 int c; 00366 00367 #ifndef CONF_VIS 00368 cputc_0('-'); 00369 #endif 00370 00371 while (!shutdown_requested()) { 00372 int clear=0; 00373 c=getchar(); 00374 00375 gotkey: 00376 00377 debugs("key "); debugw(c); 00378 debugs("task"); debugw(nb_tasks); 00379 00380 switch(c) { 00381 case KEY_ONOFF: 00382 cputs("OFF"); 00383 // Kindly request all tasks shutdown 00384 shutdown_tasks(T_USER | T_KERNEL); 00385 // Except for key_handler 00386 ctid->tflags &= (~T_SHUTDOWN); 00387 // Wait a bit 00388 clear = 50; 00389 while (--clear && (nb_tasks > 2)) 00390 msleep(100); 00391 // Wait no longer. 00392 if (nb_tasks > 2) 00393 killall(PRIO_HIGHEST); 00394 // Now key_handler should shutdown 00395 ctid->tflags |= T_SHUTDOWN; 00396 break; 00397 00398 case KEY_RUN: 00399 // toggle: start/stop program 00400 if(nb_tasks > nb_system_tasks) { 00401 // if program running, stop it 00402 clear=1; 00403 program_stop(1); 00404 } else if(program_valid(cprog)) { 00405 program_stop(0); 00406 program_run(cprog); 00407 } else { 00408 cputs("NONE"); 00409 clear=1; 00410 } 00411 break; 00412 00413 case KEY_PRGM: 00414 // works only if no programs are running. 00415 if(nb_tasks <= nb_system_tasks) { 00416 int i; 00417 for(i=0; i<PROG_MAX; i++) { 00418 if( (++cprog)>=PROG_MAX) 00419 cprog=0; 00420 if(program_valid(cprog)) 00421 break; 00422 } 00423 if(i==PROG_MAX) { 00424 cputs("NONE"); 00425 clear=1; 00426 #ifndef CONF_VIS 00427 cputc_0('-'); 00428 } 00429 else 00430 cputc_hex_0(cprog+1); 00431 #else 00432 } 00433 #endif 00434 00435 } 00436 break; 00437 case KEY_VIEW: 00438 // works only if no programs are running. 00439 if (nb_tasks > nb_system_tasks) 00440 break; 00441 /* 00442 * pressing the "view" button cycles through a display of the 00443 * amount of the amount of free memory (in decimal and 00444 * hexadecimal) and battery power. If a button other than "view" 00445 * is pressed while cycling through, we handle that button 00446 * ("goto gotkey"). 00447 */ 00448 cputs("addr"); 00449 if ((c = getchar()) != KEY_VIEW) goto gotkey; 00450 cputw(lnp_hostaddr); 00451 while ((c = getchar()) == KEY_PRGM) { 00452 lnp_hostaddr += 0x10; 00453 lnp_hostaddr &= CONF_LNP_HOSTMASK; 00454 cputw(lnp_hostaddr); 00455 } 00456 if (c != KEY_VIEW) goto gotkey; 00457 if (program_valid(cprog)) { 00458 cputs("dele"); 00459 if ((c = getchar()) != KEY_VIEW && c != KEY_PRGM) goto gotkey; 00460 if (c == KEY_PRGM) { 00461 program_t *prog=programs+cprog; 00462 if (prog->text) 00463 free(prog->text); 00464 memset(prog,0,sizeof(program_t)); 00465 cputc_0('-'); 00466 } 00467 } 00468 00469 cputs("free"); 00470 if ((c = getchar()) != KEY_VIEW) goto gotkey; 00471 lcd_int(mm_free_mem()); 00472 if ((c = getchar()) != KEY_VIEW) goto gotkey; 00473 cputw(mm_free_mem()); 00474 if ((c = getchar()) != KEY_VIEW) goto gotkey; 00475 00476 #if defined(CONF_DSENSOR) 00477 cputs("batt"); 00478 if ((c = getchar()) != KEY_VIEW) goto gotkey; 00479 lcd_int(get_battery_mv()); 00480 if ((c = getchar()) != KEY_VIEW) goto gotkey; 00481 #endif // CONF_DSENSOR 00482 00483 clear=1; 00484 break; 00485 } 00486 00487 if(clear) { 00488 wait_event(dkey_released,KEY_ANY); 00489 cls(); 00490 } 00491 } 00492 return 0; 00493 } 00494 00495 #if defined(CONF_LR_HANDLER) 00496 00497 int lrkey_handler(unsigned int etype, unsigned int key) { 00498 unsigned char pnr = 0; 00499 00500 // If a program is running, stop it 00501 // NOTE: this LRKEY is allowed while a program is running! 00502 if(key == LRKEY_STOP && etype == LREVT_KEYON && nb_tasks > nb_system_tasks) { 00503 program_stop(1); 00504 return 1; // we consumed key 00505 } 00506 00507 // Only interested if no program is running 00508 if(nb_tasks <= nb_system_tasks) { 00509 // Keydown events dispatched here 00510 if (etype == LREVT_KEYON) { 00511 switch (key) { 00512 #ifdef CONF_DSOUND 00513 case LRKEY_BEEP: 00514 // Need high pitched beep-beep 00515 dsound_system(0); 00516 break; 00517 #endif // CONF_DSOUND 00518 00519 case LRKEY_P5: 00520 pnr++; 00521 // ... Fallthru 00522 case LRKEY_P4: 00523 pnr++; 00524 // ... Fallthru 00525 case LRKEY_P3: 00526 pnr++; 00527 // ... Fallthru 00528 case LRKEY_P2: 00529 pnr++; 00530 // ... Fallthru 00531 case LRKEY_P1: 00532 // Start something? 00533 if(program_valid(pnr)) 00534 { 00535 cprog = pnr; 00536 // Reset things 00537 program_stop(0); 00538 #ifdef CONF_VIS 00539 cputc_hex_0(pnr+1); 00540 #ifndef CONF_LCD_REFRESH 00541 lcd_refresh(); 00542 #endif 00543 #endif 00544 // launch Program(n) 00545 program_run(pnr); 00546 } else { 00547 // no such program downloaded 00548 cputs("NONE"); 00549 } 00550 break; 00551 00552 #if defined(CONF_DMOTOR) 00553 // Motor on commands 00554 case LRKEY_A1: 00555 // A Motor fwd 00556 motor_a_dir(fwd); 00557 break; 00558 case LRKEY_A2: 00559 // A Motor rev 00560 motor_a_dir(rev); 00561 break; 00562 case LRKEY_B1: 00563 // B Motor fwd 00564 motor_b_dir(fwd); 00565 break; 00566 case LRKEY_B2: 00567 // B Motor rev 00568 motor_b_dir(rev); 00569 break; 00570 case LRKEY_C1: 00571 // C Motor fwd 00572 motor_c_dir(fwd); 00573 break; 00574 case LRKEY_C2: 00575 // C Motor rev 00576 motor_c_dir(rev); 00577 break; 00578 #endif // CONF_DMOTOR 00579 default: 00580 // Not consumed 00581 return 0; 00582 } 00583 #ifndef CONF_LCD_REFRESH 00584 lcd_refresh(); 00585 #endif 00586 // Key consumed 00587 return 1; 00588 } 00589 00590 // Keyup events dispatched here 00591 if (etype == LREVT_KEYOFF) { 00592 switch (key) { 00593 #if defined(CONF_DMOTOR) 00594 case LRKEY_A1: 00595 case LRKEY_A2: 00596 // Shut off A motor 00597 motor_a_dir(brake); 00598 break; 00599 case LRKEY_B1: 00600 case LRKEY_B2: 00601 // Shut off B motor 00602 motor_b_dir(brake); 00603 break; 00604 case LRKEY_C1: 00605 case LRKEY_C2: 00606 // Shut off C motor 00607 motor_c_dir(brake); 00608 break; 00609 #endif // CONF_DMOTOR 00610 case LRKEY_P1: 00611 case LRKEY_P2: 00612 case LRKEY_P3: 00613 case LRKEY_P4: 00614 case LRKEY_P5: 00615 case LRKEY_STOP: 00616 // remove the STOP (or NONE) message 00617 cls(); 00618 break; 00619 default: 00620 return 0; 00621 } 00622 // Used the key 00623 return 1; 00624 } 00625 } 00626 00627 #ifndef CONF_LCD_REFRESH 00628 lcd_refresh(); 00629 #endif 00630 // Didn't eat the key 00631 return 0; 00632 } 00633 #endif 00634 00636 00638 void program_init() { 00639 packet_len=0; 00640 sem_init(&packet_sem,0,0); 00641 execi(&packet_consumer,0,0,PRIO_HIGHEST,DEFAULT_STACK_SIZE); 00642 execi(&key_handler,0,0,PRIO_HIGHEST,DEFAULT_STACK_SIZE); 00643 00644 #ifdef CONF_LR_HANDLER 00645 // Setup kernel remote callback handler and dispatch thread 00646 lr_startup(); 00647 lr_set_handler(lrkey_handler); 00648 #endif 00649 00650 lnp_addressing_set_handler(0,&packet_producer); 00651 buffer_ptr = 0; 00652 } 00653 00655 00657 void program_shutdown() { 00658 lnp_addressing_set_handler(0,LNP_DUMMY_ADDRESSING); 00659 sem_destroy(&packet_sem); 00660 00661 #ifdef CONF_LR_HANDLER 00662 lr_shutdown(); 00663 #endif 00664 } 00665 00666 #endif // CONF_PROGRAM
brickOS is released under the
Mozilla Public License.
Original code copyright 1998-2002 by the authors. |