program.c
Go to the documentation of this file.
1
6/*
7 * The contents of this file are subject to the Mozilla Public License
8 * Version 1.0 (the "License"); you may not use this file except in
9 * compliance with the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS"
13 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
14 * License for the specific language governing rights and limitations
15 * under the License.
16 *
17 * The Original Code is legOS code, released October 17, 1999.
18 *
19 * The Initial Developer of the Original Code is Markus L. Noga.
20 * Portions created by Markus L. Noga are Copyright (C) 1999
21 * Markus L. Noga. All Rights Reserved.
22 *
23 * Contributor(s): Markus L. Noga <markus@noga.de>
24 * Frank Cremer <frank@demon.holly.nl>
25 */
26
27/*
28 * 2000.05.01 - Paolo Masetti <paolo.masetti@itlug.org>
29 *
30 * - Added "CMDirmode" for changing via LNP IR mode
31 *
32 * 2001.05.10 - Matt Ahrens <mahrens@acm.org>
33 *
34 * - Added free memory and batter life display
35 * Press "view" repeatedly while no programs are running to see
36 *
37 * 2002.4.23 - Ted Hess <thess@kitschensync.net>
38 *
39 * - Added Remote key handler
40 */
41
42#include <sys/program.h>
43
44#ifdef CONF_PROGRAM
45
46#include <sys/tm.h>
47#include <string.h>
48#include <semaphore.h>
49#include <unistd.h>
50#include <stdlib.h>
51
52#include <sys/lnp.h>
53#include <sys/lnp-logical.h>
54#include <sys/dmotor.h>
55#include <sys/dsensor.h>
56#include <sys/mm.h>
57#include <sys/battery.h>
58#include <dsound.h>
59#include <remote.h>
60
61#include <conio.h>
62
64//
65// Global Variables
66//
68
69volatile unsigned cprog;
70
72//
73// Internal Variables
74//
76
77const unsigned char min_length[]={
78 1, // CMDacknowledge
79 2, // CMDdelete
80 13, // CMDcreate
81 8, // CMDoffsets
82 4, // CMDdata
83 2, // CMDrun
84 2, // CMDirmode
85 2 // CMDsethost
86};
87
88static program_t programs[PROG_MAX];
89
90static unsigned char* buffer_ptr;
91volatile unsigned char packet_len;
92volatile unsigned char packet_src;
93
94static sem_t packet_sem;
95
96#if 0
97#define debugs(a) { cputs(a); msleep(500); }
98#define debugw(a) { cputw(a); msleep(500); }
99#else
100#define debugs(a)
101#define debugw(a)
102#endif
103
104// Forward ref
105int lrkey_handler(unsigned int etype, unsigned int key);
106
108//
109// Functions
110//
112
114
115int program_valid(unsigned nr) {
116 program_t *prog=programs+nr;
117
118 return (nr < PROG_MAX) &&
119 (prog->text_size>0) &&
120 (prog->text_size+prog->data_size==prog->downloaded);
121}
122
124static void program_run(unsigned nr) {
125 if(program_valid(nr)) {
126 program_t *prog=programs+nr;
127
128 // initialize data segments
129 //
130 memcpy(prog->data,prog->data_orig,prog->data_size);
131 memset(prog->bss,0,prog->bss_size);
132
133 execi((void*) (((char*)prog->text)
134 + prog->start ),
135 0,0,prog->prio,prog->stack_size);
136 }
137}
138
140
142static void packet_producer(const unsigned char *data,
143 unsigned char length,
144 unsigned char src) {
145 // old packet still unhandled or empty packet?
146 //
147 if(packet_len>0 || length==0)
148 return;
149
150 if (buffer_ptr != 0)
151 return;
152
153 buffer_ptr = malloc(length);
154 memcpy(buffer_ptr,data,length);
155 packet_len=length;
156 packet_src=src;
157 sem_post(&packet_sem);
158}
159
161static int packet_consumer(int argc, char *argv[]) {
162 packet_cmd_t cmd;
163 unsigned char nr=0;
164 program_t *prog=programs; // to avoid a silly warning
165 const static unsigned char acknowledge=CMDacknowledge;
166 char msg[8];
167
168 while (!shutdown_requested()) {
169 // wait for new packet
170 //
171 packet_len=0;
172 free(buffer_ptr);
173 buffer_ptr = 0;
174 if (sem_wait(&packet_sem) != -1) {
175 if (buffer_ptr == 0)
176 continue;
177
178 debugw(*(size_t*)buffer_ptr);
179
180 // handle trivial errors
181 //
182 cmd=buffer_ptr[0];
183 if (cmd>=CMDlast || packet_len<min_length[cmd])
184 continue;
185
186 // handle IR CMDs
187 if (cmd==CMDirmode) {
188 if (buffer_ptr[1]==0) {
189 debugs("nearmodeIR");
191 debugs("OK");
192 lnp_addressing_write(&acknowledge,1,packet_src,0);
193 } else {
194 debugs("farmodeIR");
196 debugs("OK");
197 lnp_addressing_write(&acknowledge,1,packet_src,0);
198 }
199 continue;
200 }
201
202 // Is this a request to change host address
203 if (cmd == CMDsethost) {
204 // ACK before we change our address
205 lnp_addressing_write(&acknowledge,1,packet_src,0);
206 lnp_set_hostaddr(buffer_ptr[1]);
207 continue;
208 }
209
210 // Get program number, validate value
211 if((cmd > CMDacknowledge) && (cmd <= CMDrun)) {
212 nr = buffer_ptr[1];
213 if(nr > PROG_MAX)
214 continue;
215#ifndef CONF_VIS
216 cputc_hex_0(nr+1);
217#endif
218 }
219
220 debugw(nr);
221 prog = programs+nr;
222
223 switch( cmd ) {
224 case CMDdelete:
225 debugs("dele");
226
228 if(prog->text)
229 free(prog->text);
230 memset(prog,0,sizeof(program_t));
231
232#ifndef CONF_VIS
233 if(nr == cprog)
234 cputc_0('-');
235#endif
236 debugs("OK");
237
238 lnp_addressing_write(&acknowledge,1,packet_src,0);
239 }
240 break;
241
242 case CMDcreate:
243 debugs("crea");
244 if(!prog->text) {
245 memcpy(&(prog->text_size),buffer_ptr+2,11);
246
247 if((prog->text=malloc(prog->text_size+
248 2*prog->data_size+
249 prog->bss_size ))) {
250 prog->data=prog->text+prog->text_size;
251 prog->bss=prog->data+prog->data_size;
252 prog->data_orig=prog->bss +prog->bss_size;
253 prog->downloaded=0;
254
255 debugs("OK");
256
257 cputw(0);
258 cprog = nr;
259
260 msg[0]=CMDacknowledge;
261 msg[1]=nr;
262 memcpy(msg+2,prog,6);
263 lnp_addressing_write(msg,8,packet_src,0);
264 } else
265 memset(prog,0,sizeof(program_t));
266 }
267 break;
268
269 case CMDdata:
270 debugs("data");
271 if(prog->text && !program_valid(nr)) {
272 size_t offset=*(size_t*)(buffer_ptr+2);
273 if(offset<=prog->downloaded) {
274 if(offset==prog->downloaded) {
275 memcpy(prog->text+offset,buffer_ptr+4,packet_len-4);
276 prog->downloaded+=packet_len-4;
277
278 if(program_valid(nr)) {
279 // copy original data segment and we're done.
280 //
281 memcpy(prog->data_orig,prog->data,prog->data_size);
282 cls();
283 } else
284 cputw(prog->downloaded);
285 debugs("OK");
286 } else
287 debugs("OLD");
288
289 lnp_addressing_write(&acknowledge,1,packet_src,0);
290 }
291 }
292 break;
293
294 case CMDrun:
295 debugs("run");
296 if(program_valid(nr)) {
297 cprog = nr;
298 program_stop(0);
299 program_run(nr);
300
301 debugs("OK");
302 lnp_addressing_write(&acknowledge,1,packet_src,0);
303 }
304 break;
305
306 default:
307 debugs("error");
308 }
309 }
310 }
311 free(buffer_ptr);
312 return 0;
313}
314
316void program_stop(int flag) {
317 int count_down = 40;
318
319 // Kindly request that all user tasks shutdown
320 shutdown_tasks(T_USER);
321 // Wait a bit
322 while (--count_down && (nb_tasks > nb_system_tasks)) {
323 if (flag)
324 cputs("STOP");
325 msleep(100);
326 }
327
329 // Wait no longer.
330 if (flag) {
331 cputs("KILL");
332 // display immediately
333 lcd_refresh();
334 }
335 killall(PRIO_HIGHEST-1);
336 }
337
338 // Reset motors, sensors, sound & LNP as
339 // programs may have motors running,
340 // sensors active or handlers set.
341 //
342 // Programs that exit on their own
343 // are assumed to take the necessary
344 // actions themselves.
345 //
346#ifdef CONF_DSOUND
347 dsound_stop();
348#endif
349#ifdef CONF_DMOTOR
350 dm_init();
351#endif
352#ifdef CONF_DSENSOR
353 ds_init();
354#endif
355 lnp_init();
356#ifdef CONF_LR_HANDLER
357 // Reset remote button handler
358 lr_init();
359 lr_set_handler(lrkey_handler);
360#endif
361}
362
364int key_handler(int argc, char *argv[]) {
365 int c;
366
367#ifndef CONF_VIS
368 cputc_0('-');
369#endif
370
371 while (!shutdown_requested()) {
372 int clear=0;
373 c=getchar();
374
375gotkey:
376
377 debugs("key "); debugw(c);
378 debugs("task"); debugw(nb_tasks);
379
380 switch(c) {
381 case KEY_ONOFF:
382 cputs("OFF");
383 // Kindly request all tasks shutdown
384 shutdown_tasks(T_USER | T_KERNEL);
385 // Except for key_handler
386 ctid->tflags &= (~T_SHUTDOWN);
387 // Wait a bit
388 clear = 50;
389 while (--clear && (nb_tasks > 2))
390 msleep(100);
391 // Wait no longer.
392 if (nb_tasks > 2)
393 killall(PRIO_HIGHEST);
394 // Now key_handler should shutdown
396 break;
397
398 case KEY_RUN:
399 // toggle: start/stop program
401 // if program running, stop it
402 clear=1;
403 program_stop(1);
404 } else if(program_valid(cprog)) {
405 program_stop(0);
406 program_run(cprog);
407 } else {
408 cputs("NONE");
409 clear=1;
410 }
411 break;
412
413 case KEY_PRGM:
414 // works only if no programs are running.
416 int i;
417 for(i=0; i<PROG_MAX; i++) {
418 if( (++cprog)>=PROG_MAX)
419 cprog=0;
421 break;
422 }
423 if(i==PROG_MAX) {
424 cputs("NONE");
425 clear=1;
426#ifndef CONF_VIS
427 cputc_0('-');
428 }
429 else
431#else
432 }
433#endif
434
435 }
436 break;
437 case KEY_VIEW:
438 // works only if no programs are running.
440 break;
441 /*
442 * pressing the "view" button cycles through a display of the
443 * amount of the amount of free memory (in decimal and
444 * hexadecimal) and battery power. If a button other than "view"
445 * is pressed while cycling through, we handle that button
446 * ("goto gotkey").
447 */
448 cputs("addr");
449 if ((c = getchar()) != KEY_VIEW) goto gotkey;
451 while ((c = getchar()) == KEY_PRGM) {
452 lnp_hostaddr += 0x10;
455 }
456 if (c != KEY_VIEW) goto gotkey;
457 if (program_valid(cprog)) {
458 cputs("dele");
459 if ((c = getchar()) != KEY_VIEW && c != KEY_PRGM) goto gotkey;
460 if (c == KEY_PRGM) {
461 program_t *prog=programs+cprog;
462 if (prog->text)
463 free(prog->text);
464 memset(prog,0,sizeof(program_t));
465 cputc_0('-');
466 }
467 }
468
469 cputs("free");
470 if ((c = getchar()) != KEY_VIEW) goto gotkey;
472 if ((c = getchar()) != KEY_VIEW) goto gotkey;
474 if ((c = getchar()) != KEY_VIEW) goto gotkey;
475
476#if defined(CONF_DSENSOR)
477 cputs("batt");
478 if ((c = getchar()) != KEY_VIEW) goto gotkey;
480 if ((c = getchar()) != KEY_VIEW) goto gotkey;
481#endif // CONF_DSENSOR
482
483 clear=1;
484 break;
485 }
486
487 if(clear) {
489 cls();
490 }
491 }
492 return 0;
493}
494
495#if defined(CONF_LR_HANDLER)
497int lrkey_handler(unsigned int etype, unsigned int key) {
498 unsigned char pnr = 0;
499
500 // If a program is running, stop it
501 // NOTE: this LRKEY is allowed while a program is running!
502 if(key == LRKEY_STOP && etype == LREVT_KEYON && nb_tasks > nb_system_tasks) {
503 program_stop(1);
504 return 1; // we consumed key
505 }
506
507 // Only interested if no program is running
509 // Keydown events dispatched here
510 if (etype == LREVT_KEYON) {
511 switch (key) {
512#ifdef CONF_DSOUND
513 case LRKEY_BEEP:
514 // Need high pitched beep-beep
515 dsound_system(0);
516 break;
517#endif // CONF_DSOUND
518
519 case LRKEY_P5:
520 pnr++;
521 // ... Fallthru
522 case LRKEY_P4:
523 pnr++;
524 // ... Fallthru
525 case LRKEY_P3:
526 pnr++;
527 // ... Fallthru
528 case LRKEY_P2:
529 pnr++;
530 // ... Fallthru
531 case LRKEY_P1:
532 // Start something?
533 if(program_valid(pnr))
534 {
535 cprog = pnr;
536 // Reset things
537 program_stop(0);
538#ifdef CONF_VIS
539 cputc_hex_0(pnr+1);
540#ifndef CONF_LCD_REFRESH
541 lcd_refresh();
542#endif
543#endif
544 // launch Program(n)
545 program_run(pnr);
546 } else {
547 // no such program downloaded
548 cputs("NONE");
549 }
550 break;
551
552#if defined(CONF_DMOTOR)
553 // Motor on commands
554 case LRKEY_A1:
555 // A Motor fwd
557 break;
558 case LRKEY_A2:
559 // A Motor rev
561 break;
562 case LRKEY_B1:
563 // B Motor fwd
565 break;
566 case LRKEY_B2:
567 // B Motor rev
569 break;
570 case LRKEY_C1:
571 // C Motor fwd
573 break;
574 case LRKEY_C2:
575 // C Motor rev
577 break;
578#endif // CONF_DMOTOR
579 default:
580 // Not consumed
581 return 0;
582 }
583#ifndef CONF_LCD_REFRESH
584 lcd_refresh();
585#endif
586 // Key consumed
587 return 1;
588 }
589
590 // Keyup events dispatched here
591 if (etype == LREVT_KEYOFF) {
592 switch (key) {
593#if defined(CONF_DMOTOR)
594 case LRKEY_A1:
595 case LRKEY_A2:
596 // Shut off A motor
598 break;
599 case LRKEY_B1:
600 case LRKEY_B2:
601 // Shut off B motor
603 break;
604 case LRKEY_C1:
605 case LRKEY_C2:
606 // Shut off C motor
608 break;
609#endif // CONF_DMOTOR
610 case LRKEY_P1:
611 case LRKEY_P2:
612 case LRKEY_P3:
613 case LRKEY_P4:
614 case LRKEY_P5:
615 case LRKEY_STOP:
616 // remove the STOP (or NONE) message
617 cls();
618 break;
619 default:
620 return 0;
621 }
622 // Used the key
623 return 1;
624 }
625 }
626
627#ifndef CONF_LCD_REFRESH
628 lcd_refresh();
629#endif
630 // Didn't eat the key
631 return 0;
632}
633#endif
634
636
638void program_init() {
639 packet_len=0;
640 sem_init(&packet_sem,0,0);
641 execi(&packet_consumer,0,0,PRIO_HIGHEST,DEFAULT_STACK_SIZE);
642 execi(&key_handler,0,0,PRIO_HIGHEST,DEFAULT_STACK_SIZE);
643
644#ifdef CONF_LR_HANDLER
645 // Setup kernel remote callback handler and dispatch thread
646 lr_startup();
647 lr_set_handler(lrkey_handler);
648#endif
649
650 lnp_addressing_set_handler(0,&packet_producer);
651 buffer_ptr = 0;
652}
653
655
657void program_shutdown() {
659 sem_destroy(&packet_sem);
660
661#ifdef CONF_LR_HANDLER
662 lr_shutdown();
663#endif
664}
665
666#endif // CONF_PROGRAM
Internal Interface: battery handling.
int get_battery_mv()
get current battery voltage
#define CONF_LNP_HOSTMASK
LNP host mask.
Definition config.h:58
Interface: console input / output.
void cputw(unsigned word)
Write a HEX word to LCD.
void cputc_hex_0(unsigned nibble)
write HEX digit to position 0 of LCD
Definition conio.h:128
void cls()
clear user portion of LCD
void cputc_0(unsigned c)
write ASCII char to position 0 of LCD
Definition conio.h:174
void cputs(char *s)
Write string s to LCD (Only first 5 chars)
wakeup_t dkey_released(wakeup_t data)
wakeup if all of the given keys are released.
#define KEY_PRGM
the program key is pressed
Definition dkey.h:47
#define KEY_RUN
the run key is pressed
Definition dkey.h:45
#define KEY_ANY
any of the keys
Definition dkey.h:49
#define KEY_ONOFF
the on/off key is pressed
Definition dkey.h:44
int getchar()
wait for keypress and return key code.
#define KEY_VIEW
the view key is pressed
Definition dkey.h:46
void motor_b_dir(MotorDirection dir)
set motor B direction to dir
@ fwd
forward
Definition dmotor.h:46
@ rev
reverse
Definition dmotor.h:47
@ brake
hold current position
Definition dmotor.h:48
void motor_a_dir(MotorDirection dir)
set motor A direction to dir
void motor_c_dir(MotorDirection dir)
set motor C direction to dir
static void dsound_system(unsigned nr)
play a system sound
Definition dsound.h:240
void dsound_stop(void)
stop playing sound
void lcd_refresh(void)
refresh the entire LCD display
Definition lcd.c:254
void lnp_logical_range(int far)
Set the IR transmitter range.
Definition lnp-logical.h:62
unsigned char lnp_hostaddr
LNP host address.
#define LNP_DUMMY_ADDRESSING
dummy addressing layer packet handler
Definition lnp.h:61
void lnp_set_hostaddr(unsigned char host)
set new LNP host address
Definition lnp.h:115
void lnp_addressing_set_handler(unsigned char port, lnp_addressing_handler_t handler)
set an addressing layer packet handler for a port.
Definition lnp.h:107
int lnp_addressing_write(const unsigned char *data, unsigned char length, unsigned char dest, unsigned char srcport)
send a LNP addressing layer packet of given length
Internal Interface: memory management.
int mm_free_mem(void)
how many bytes of memory are free?
Internal Interface: program data structures and functions.
#define PROG_MAX
maximum number of programs
Definition program.h:45
int program_valid(unsigned nr)
check if a given program is valid.
packet_cmd_t
Definition program.h:71
@ CMDrun
1+ 1: b[nr]
Definition program.h:79
@ CMDdelete
1+ 1: b[nr]
Definition program.h:73
@ CMDlast
?
Definition program.h:82
@ CMDsethost
1+ 1: b[hostaddr]
Definition program.h:81
@ CMDdata
1+>3: b[nr] s[offset] array[data]
Definition program.h:78
@ CMDirmode
1+ 1: b[0=near/1=far]
Definition program.h:80
@ CMDcreate
1+12: b[nr] s[textsize] s[datasize]
Definition program.h:74
@ CMDacknowledge
1:
Definition program.h:72
void program_shutdown()
shutdown program support
void program_init()
initialize program support
volatile unsigned cprog
the current program
void program_stop(int flag)
stop program
Interface: LEGO Infrared Remote Control.
#define LRKEY_B1
Motor-B forward (up)
Definition remote.h:45
#define LRKEY_A1
Motor-A forward (up)
Definition remote.h:43
#define LRKEY_B2
Motor-B reverse (down)
Definition remote.h:51
#define LRKEY_P3
Run Program 3.
Definition remote.h:59
void lr_startup(void)
start the LEGO IR Remote subsystem
#define LRKEY_A2
Motor-A reverse (down)
Definition remote.h:49
void lr_set_handler(lr_handler_t handler)
set a new handler for LEGO IR Remote messages
Definition remote.h:97
#define LRKEY_C2
Motor-C reverse (down)
Definition remote.h:53
#define LRKEY_P5
Run Program 5.
Definition remote.h:63
#define LRKEY_P1
Run Program 1.
Definition remote.h:55
#define LRKEY_C1
Motor-C forward (up)
Definition remote.h:47
#define LRKEY_STOP
Stop key.
Definition remote.h:65
@ LREVT_KEYON
a key on the remote was pressed
Definition remote.h:71
@ LREVT_KEYOFF
a key on the remote was released
Definition remote.h:72
void lr_init(void)
initialize the LEGO IR Remote subsystem
#define LRKEY_P4
Run Program 4.
Definition remote.h:61
#define LRKEY_BEEP
Beep Key.
Definition remote.h:67
void lr_shutdown(void)
stop the LEGO IR Remote subsystem
#define LRKEY_P2
Run Program 2.
Definition remote.h:57
#define lcd_int(i)
display an integer in decimal
Definition lcd.h:123
Interface: POSIX 1003.1b semaphores for task synchronization.
int sem_post(sem_t *sem)
Post a semaphore.
Definition semaphore.h:123
int sem_init(sem_t *sem, int pshared, unsigned int value)
Initialize a semaphore.
Definition semaphore.h:64
int sem_destroy(sem_t *sem)
We're done with the semaphore, destroy it.
Definition semaphore.h:147
int sem_wait(sem_t *sem)
Wait for semaphore (blocking)
atomic_t sem_t
the semaphore data-type
Definition semaphore.h:46
Interface: reduced standard C library.
void * malloc(size_t size)
allocate and return pointer to uninitialized memory
void free(void *ptr)
return the allocated memory to memory management.
Interface: string functions.
void * memcpy(void *dest, const void *src, size_t size)
copy memory block from src to dest.
void * memset(void *s, int c, size_t n)
fill memory block with a byte value.
tflags_t tflags
task flags
Definition tm.h:109
The program control structure.
Definition program.h:52
priority_t prio
priority to run this program at
Definition program.h:63
size_t stack_size
stack segment size in bytes
Definition program.h:61
void * bss
origin of bss segment (imm. after data)
Definition program.h:55
void * text
origin of text segment
Definition program.h:53
void * data
origin of data segment (imm. after text)
Definition program.h:54
size_t downloaded
number of bytes downloaded so far.
Definition program.h:65
size_t data_size
data segment size in bytes
Definition program.h:59
size_t text_size
text segment size in bytes
Definition program.h:58
void * data_orig
origin of backup copy of data segment
Definition program.h:56
size_t start
offset from text segment to start into.
Definition program.h:62
size_t bss_size
bss segment size in bytes
Definition program.h:60
Internal Interface: direct motor control.
void dm_init(void)
initialize motors
Internal Interface: direct sensor access.
void ds_init(void)
initialize sensor a/d conversion
Internal LNP Interface: link networking protocol logical layer.
Internal LNP Interface: link networking protocol.
void lnp_init(void)
Initialise protocol handlers.
Internal Interface: task management.
volatile unsigned int nb_tasks
number of tasks
volatile unsigned int nb_system_tasks
tdata_t * ctid
ptr to current process data
#define T_SHUTDOWN
shutdown requested
Definition tm.h:78
#define shutdown_requested()
test to see if task has been asked to shutdown
Definition tm.h:134
#define PRIO_HIGHEST
The highest possible task priority.
Definition tm.h:55
#define DEFAULT_STACK_SIZE
that's enough.
Definition tm.h:81
#define T_KERNEL
task flags
Definition tm.h:75
#define T_USER
user task
Definition tm.h:76
Interface: reduced UNIX standard library.
wakeup_t wait_event(wakeup_t(*wakeup)(wakeup_t), wakeup_t data)
Definition unistd.h:112
#define msleep(s)
Definition unistd.h:123

brickOS is released under the Mozilla Public License.
Original code copyright 1998-2005 by the authors.

Generated for brickOS Kernel Developer by doxygen 1.9.8