logbook
legOS

legOS, the: [unauth, unoff] independent LEGO Mindstorms OS. Offers preemptive multitasking, energy saving, dynamic memory management, POSIX semaphores, native access to display, buttons, IR communication, motors and sensors.

 
 
  Jan 29th

Released legOS-0.1.6 incorporating the contributions.

  Jan 28th

Contributions! And V0.1.5 is only a day old...

Michael Nielsen
Fixed sound driver IRQ bug
Chris Dearman
Fixed the ugly volatile problem in the IR code
Eric Habnerfeller
Fixed rotation sensors with window-based approach (validation pending)

With the kind aid of Ben Laurie, public CVS should be up again soon. I'll post instructions as soon as possible. For now, just be patient for a while and wait for 0.1.6 ;-)

Linux/glibc binaries of the H8 tool suite are finally available for download. They should work with RedHat 5.0 / SuSE 6.0 and above.

  Jan 27th

I've finally found an apartment in Karlsruhe, bought several necessities of daily life, such as a bed, and got the telco people to hook up my phone. Gee, what are all these boxes still doing here?

legOS-0.1.5 is out. It's mostly a maintenance release. Changes include:

  • added 32 bit system timer sys_time with 1ms resolution. Never mind Y2K - we have a 49.7 day problem.
  • rewrote task switcher to free 8-bit timer 1. Now IR compatible.
  • fixed memory management bugs that crashed demos when running them for the 5th time. (It was the pointer mm_first_free, I had conditionally defined out the code that updated it. Sigh.)
  • fixed IR driver. It seems the carrier has to be turned on exclusively when sending, otherwise reception doesn't work. Added fflush() command.
  • new demo tm-and-ir.c receives and displays IR at 2400 / 8N1. Broadcasts "Hello, world!" messages when view is pressed. Press Run to start/stop.
 
  Dec 12th

gcc exhibits horrible bugs. It refuses flat-out to cooperate on the subject of register clobbers

  • when allocating an explicit register variable via
    register unsigned _asdf __asm__ ("r6");
  • when specifying register clobbers in an asm statement like
    __asm__ __volatile__ ("mov.w #0x1234,r6":::"r6");
  • gcc doesn't save and restore the clobbered register at all! It should do so in any case, because h8300.h in the gcc-2.8.1/config/h8300/ directory specifies r4,r5 and r6 as call-safe registers - even leaf functions *must* restore their contents when using them.

    For now, I am circumventing this with wrapper functions to add stability. The generated code isn't pretty, but I can't help it.

    Re-scaled the light sensor values to 0-100. Experimental support for rotation sensors - as I don't have any, I cannot verify if they work.

     
      Dec 10th

    As the date suggests, I've been busy over the past few weeks. There may be exciting projects coming up, so stay tuned.

    Added support for active light sensors today, which required a complete re-write of the ISR.

    I tried several different approaches. The one that seems to work best is to deactivate an output upon A/D conversion start and reactivate it upon completion should the sensor mode be set accordingly.

    Current release version is 0.1.3.

     
      Nov 19th

    Sorted the task list by priorities. Introduced speedup for the case that no two priorities are equal. That made some ugly interfaces obsolete.

    legOS is in CVS now. Current release version is 0.1.2.

     
      Nov 16th

    Baptised the child legOS and shipped V0.1. POSIX semaphores should work now, the power-saving idle process, zero CPU usage sleep(sec) and msleep(msec) and Ben's priority scheduler apparently do. Implemented A/D input to read sensors. Killed the assembler prelude and trailer. Fixed memory management bugs.

     
      Nov 14th

    Implemented kill(pid_t pid) and wait_event(int (*wakeup)(int)). The latter allows suspension of programs until an arbitrary event function returns a nonzero value. Power saving mode in case all tasks are waiting is around the corner... current archive is tm3.tgz, a demo with three tasks that wait for the run button, display some numbers and drive motors A,C is here: tm2-test.srec. If you can tell me why it crashes at the end, go ahead.

    IR and task management are still incompatible. But tomorrow is a new day.

     
      Nov 13th

    As people on the newsgroup determined 0xf000 to be the memory mapped I/O address for the motor outputs, I whipped up a native motor driver. Current archive: direct-motor.tgz, compiled demo: dm-test.srec.

    The motor IRQ driver overrides the 16-bit timer OCIA IRQ, that is, ROM motor and sound drivers cease to function. I'll hook in my task switcher tomorrow, so the only thing missing will be sound and sensors.

    I wrote a direct sound driver yesterday, but the LEGO speaker seems to be too reactive for the usual approach when playing sound on the PC speaker. Right now, there's 1 bit / 8 kHz output, and it sounds horrible. That's why I'm not posting it yet.

    People keep asking me, why don't you do this-and-that via ROM?. Well, the answer is, doing it in a custom kernel is considerably faster and more flexible. For those worried about the memory footprint: with every option linked in, even the currently mutually exclusive ones, the s-record kernel is only 8652 bytes. That's about 4k of RAM on the RCX, as in: 28k left. Objections?

     
      Nov 9th

    Got IR transmission to work. The IR read demo was somehow deleted in the process, but dir_read(ptr,len) and dir_write(ptr,len) should compensate for that. For sources, see direct-ir.tgz A simple send demo that keeps sending "Hello, world!\n" is available as an executable: dir-test.srec. Rudimentary collision detection is already implemented. Sent packets should be identically received on the RCX, and that is checked. The collision count is shown on the RCX display in the demo.

    Here's a butchered version of Kekoa's send.c called send-raw.c that can read (if called without arguments) and write (if called with arguments) the RCX port in raw mode. Beware: if the Lego IR tower powers down and its green LED goes off, the PC can't receive anymore. So whatever packet format we establish, we'll need libs for the PC to implement some sort of keepalive. Right now, just open a second shell and send any raw byte to power up again. This will show up in the collision count.

    Press Run to stop the demo. Further new tidbits: to erase the firmware, press Program + On/Off when stopped. No more removing batteries - unless you crash...

    Caveats: the IR carrier is generated by 8 bit counter 1. That's the same one I was using for the task switcher, so these packages are mutually exclusive at the moment. I'll move the task switcher to the 16 bit counter soon. Promise. The buffer overflows will sometime be fixed,too.

     
      Nov 6th

    The IR can be read directly now. First tests seem to indicate that 4800 baud transmission is feasible. With a different loader, 4x faster program download might be around the corner. I'll implement transmission next week.

    When the battling creatures kit becomes available, erase firmware might be of interest to the experienced... Switching on high power IR and sending 0xff several times upon detection of a standard RCX header might also be an interesting case study for ECM.

     
      Nov 5th

    I redesigned memory management. The bitfields are gone, memory can be allocated down to two bytes. Just four bytes overhead per block (length, owner), with owner 0x0000 signifying free and 0xffff reserved blocks. There's garbage collection at task death, too.

    Speaking of which. Fully preemptive multitasking. Set up tasks with execi(start_address,stack_length) to execute images in memory. Then call tm_start() to run the task manager. When all tasks have terminated, you're back in single tasking mode.

    There's just a couple of minor flaws. First and foremost, malloc() isn't tasksafe. But semaphores and critical section locks are around the corner. Then, there's no way for tasks to wait for events. I'm thinking about implementing wait(event_fn), with event_fn being arbitrary user code. The task manager just calls it every once in a while. Until the function returns a non-zero value, the task is going to take no processor time whatsoever. Also, memory layout is very strict right now - everything above 0xc000 is off limits. The macros should make it easy changing that.

    Enough spoken, here's tm-0.1.tgz and a compiled demo tm-test.srec. Push Run to run. The demo starts two tasks that show 2222 and 5555 resp. on the display. The 2222 task stops first, then the other one. The running man is created by the task scheduler. Notice the occasional display corruptions when interrupting lcd_refresh(). Maybe refresh should become an kernel function.

    The demo takes 6440 bytes in S-record format, that's about 3K on the RCX. Everything is linked in, ASCII and hexadecimal output, memory and task management. Maybe we'll get sockets and NFS, afterall.

     
      Nov 3rd

    Never mind the ROM. I figured out how to read button states directly from the digital inputs. Details in direct-button.h, and here's a compiled demo: btest.srec. Press Run to run the viewer. It'll display the button states. Press View to quit. Repeat ad infinitum, then press On/Off to power down.

     
      Nov 2nd

    The gnu linker stubbornly insisted on placing read-only data in front of my text segment. I forced it to reconsider. You shouldn't need other linker flags than -T h8300.rcx anymore.

    Figured out the kernel data structures for individual LCD segments. You can control everything now. Only display refresh still necessitates a ROM call. The headers direct-lcd.h and bitops.h contain all the information you need. There's a C demo dlcd-test.c. A compiled version, dlcd-test.srec, is available.

    Console output is working now. There is a strange glitch with the first few characters of cputs(), but maybe one of you will see what I don't. Files: conio.h, conio.c, conio-test.c. My current Makefile should help you compiling this, if not, try the compiled conio-test.srec.

    alltogether.tgz  
      Nov 1st

    We're on our way to a kernel - I have dynamic memory management running now. You get malloc(),calloc(), realloc() and free().

    I cut the assembler down to half a page and lots of inline functions, the rest is pure C now. There is a nice void kmain(void) that runs the basic stuff. User level code is called at int main(void) now, and after termination, the exit code will be displayed.

    Right now, the demo application allocates, reallocates and frees several memory areas, forgetting to free most of them. It also displays the addresses. This is interesting because they will increase with every run, thereby demonstrating memory leaks. (That's why it I have it return an exit code of -1).

    I'm also 50% finished writing POSIX semaphores. Someone clear me up on the NMI, please. Can I ignore that?

    Just about every file changed, and many new ones were added. Just get the new distribution kernel1.tgz. If your browser displays garbage at this link, try using the right mouse button menu to download it directly. Ignore the warnings about memcpy() redefinitions, they're not important.

     
      Oct 31st

    The new RCX native gcc header to control the LCD is here: rcx-lcd.h. All display modes supported, including signed/unsigned data, decimal points, leading zeros etc. You also need the Makefile and the assembler files from the older firm-gcc2.tgz if you don't have them already.

    Hello (,world!) is available as C source. The compiled firmware somehow disappeared.

     

    counter