Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

kernel/program.c

Go to the documentation of this file.
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.

Generated on Mon Feb 16 21:02:10 2004 for brickOS Kernel Developer by doxygen 1.3.5