aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2011-03-11 01:28:00 +0000
committerDimitri Sokolyuk <demon@dim13.org>2011-03-11 01:28:00 +0000
commitb8335062ae7d19bd27e6131fadcd7d3a116c4992 (patch)
tree3bd226885fb6f2ca24ee300a44d7b51ffb8d2706
DimOS RT
-rw-r--r--Makefile5
-rw-r--r--bootloader/Makefile5
-rw-r--r--bootloader/Makefile.inc6
-rw-r--r--bootloader/bootloader.c94
-rw-r--r--bootloader/bootloader.h39
-rw-r--r--bootloader/bootloader/Makefile7
-rw-r--r--bootloader/dump.c60
-rw-r--r--bootloader/hexdump/Makefile7
-rw-r--r--bootloader/ihex.c93
-rw-r--r--bootloader/mem.c69
-rw-r--r--bootloader/memdump/Makefile7
-rw-r--r--bootloader/tty.c80
-rw-r--r--firmware/Makefile61
-rw-r--r--firmware/firmware.c104
-rw-r--r--kernel/Makefile64
-rw-r--r--kernel/heartbeat.c53
-rw-r--r--kernel/hsv.c25
-rw-r--r--kernel/kernel.c297
-rw-r--r--kernel/kernel.h80
-rw-r--r--kernel/lcd3.c184
-rw-r--r--kernel/main.c52
-rw-r--r--kernel/rgb.c79
-rw-r--r--kernel/stack.h99
-rw-r--r--kernel/tasks.h39
-rw-r--r--kernel/uart.c80
25 files changed, 1689 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0bbec38
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+SUBDIR = bootloader firmware kernel
+
+.include <bsd.subdir.mk>
diff --git a/bootloader/Makefile b/bootloader/Makefile
new file mode 100644
index 0000000..ddf36a5
--- /dev/null
+++ b/bootloader/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+SUBDIR= bootloader hexdump memdump
+
+.include <bsd.subdir.mk>
diff --git a/bootloader/Makefile.inc b/bootloader/Makefile.inc
new file mode 100644
index 0000000..772968c
--- /dev/null
+++ b/bootloader/Makefile.inc
@@ -0,0 +1,6 @@
+# $Id$
+
+.PATH: ${.CURDIR}/..
+CFLAGS+=-I${.CURDIR}/..
+DEBUG+= -Wall -ggdb
+NOMAN=
diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c
new file mode 100644
index 0000000..d83db57
--- /dev/null
+++ b/bootloader/bootloader.c
@@ -0,0 +1,94 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "bootloader.h"
+
+int
+transfer(int fd, struct page *p, int pages, int pagesize)
+{
+ int n, off;
+
+ fprintf(stderr, "trying to reboot device\n");
+ usleep(500);
+ put('R', fd); /* try to reboot */
+ usleep(500);
+
+ fprintf(stderr, "waiting for bootloader ");
+ do {
+ put('P', fd);
+ twiddle();
+ } while (get(fd) != 'p');
+
+ fprintf(stderr, "\nwriting: ");
+
+ for (n = 0; n < pages; n++) {
+ fprintf(stderr, "%c", ".o"[p[n].dirty]);
+ if (p[n].dirty) {
+ put('D', fd);
+ put(n, fd);
+ for (off = 0; off < pagesize; off++)
+ put(p[n].data[off], fd);
+ assert (get(fd) == 'd');
+ }
+ }
+ fprintf(stderr, "\nrebooting\n");
+ put('R', fd);
+
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct page *p;
+ char *dev = "/dev/ttyU0";
+ int c, fd;
+
+ while ((c = getopt(argc, argv, "f:")) != -1)
+ switch (c) {
+ case 'f':
+ dev = strdup(optarg);
+ break;
+ default:
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ return -1;
+
+ p = rdhex(argv[0], PAGENUM, PAGESIZE);
+ assert(p);
+ assert(p[120].dirty == 0); /* protect firmware */
+
+ fd = open_tty(dev);
+ if (fd == -1)
+ perror(dev);
+ transfer(fd, p, PAGENUM, PAGESIZE);
+ close(fd);
+
+ freehex(p, PAGENUM);
+
+ return 0;
+}
diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h
new file mode 100644
index 0000000..1af5364
--- /dev/null
+++ b/bootloader/bootloader.h
@@ -0,0 +1,39 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __BOOTLOADER_H
+#define __BOOTLOADER_H
+
+#define PAGESIZE 64
+#define PAGENUM 128
+#define RAMEND 0x45F
+
+struct page {
+ unsigned char *data;
+ int dirty;
+};
+
+struct page *rdhex(char *, int, int);
+void freehex(struct page *, int);
+
+void put(unsigned char c, int fd);
+unsigned char get(int fd);
+void twiddle(void);
+int open_tty(char *dev);
+void close_tty(int fd);
+
+#endif
diff --git a/bootloader/bootloader/Makefile b/bootloader/bootloader/Makefile
new file mode 100644
index 0000000..d12e9fb
--- /dev/null
+++ b/bootloader/bootloader/Makefile
@@ -0,0 +1,7 @@
+# $Id$
+
+PROG= bootloader
+SRCS= bootloader.c ihex.c tty.c
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/bootloader/dump.c b/bootloader/dump.c
new file mode 100644
index 0000000..3d675f4
--- /dev/null
+++ b/bootloader/dump.c
@@ -0,0 +1,60 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bootloader.h"
+
+void
+dumphex(struct page *p, int pages, int pagesize)
+{
+ int n, off, used = 0;
+
+ for (n = 0; n < pages; n++) {
+ if (p[n].dirty) {
+ ++used;
+ printf("page %3d (%.4x)", n, n * pagesize);
+ for (off = 0; off < pagesize; off++) {
+ if (off % 16 == 0)
+ printf("\n");
+ printf("%3.2x", p[n].data[off]);
+ }
+ printf("\n");
+ }
+ }
+
+ printf("used: %3d/%3d (%5.2f%%)\n", used, pages,
+ 100 * used / (float)pages);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct page *p;
+
+ if (argc != 2)
+ return -1;
+
+ p = rdhex(argv[1], PAGENUM, PAGESIZE);
+ assert(p);
+ dumphex(p, PAGENUM, PAGESIZE);
+ freehex(p, PAGENUM);
+
+ return 0;
+}
diff --git a/bootloader/hexdump/Makefile b/bootloader/hexdump/Makefile
new file mode 100644
index 0000000..c72213a
--- /dev/null
+++ b/bootloader/hexdump/Makefile
@@ -0,0 +1,7 @@
+# $Id$
+
+PROG= dump
+SRCS= dump.c ihex.c
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/bootloader/ihex.c b/bootloader/ihex.c
new file mode 100644
index 0000000..4348910
--- /dev/null
+++ b/bootloader/ihex.c
@@ -0,0 +1,93 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bootloader.h"
+
+int
+rdbyte(char **s, int *sum)
+{
+ int x;
+
+ sscanf(*s, "%2x", &x);
+
+ *s += 2;
+ *sum += x;
+
+ return x;
+}
+
+struct page *
+rdhex(char *fname, int pages, int pagesize)
+{
+ struct page *p;
+ FILE *fd;
+ uint i, length, addr, addrh, addrl, cksum, page, off;
+ char *s, buf[80];
+
+ fd = fopen(fname, "r");
+ if (!fd)
+ return NULL;
+
+ p = calloc(pages, sizeof(struct page));
+
+ while ((s = fgets(buf, sizeof(buf), fd)) != NULL) {
+ if (*s++ != ':')
+ continue;
+
+ cksum = 0;
+ length = rdbyte(&s, &cksum);
+ addrh = rdbyte(&s, &cksum);
+ addrl = rdbyte(&s, &cksum);
+ if (rdbyte(&s, &cksum)) /* type, has to be 0 (DATA) */
+ continue;
+
+ addr = (addrh << 8) | addrl;
+ for (i = 0; i < length; i++) {
+ page = (addr + i) / pagesize;
+ off = (addr + i) % pagesize;
+ if (!p[page].dirty) {
+ p[page].data = malloc(pagesize);
+ memset(p[page].data, 0xff, pagesize);
+ }
+ p[page].data[off] = rdbyte(&s, &cksum);
+ p[page].dirty = 1;
+ }
+
+ rdbyte(&s, &cksum); /* checksum, last byte */
+ if (cksum & 0xff)
+ return NULL;
+ }
+
+ fclose(fd);
+
+ return p;
+}
+
+void
+freehex(struct page *p, int pages)
+{
+ int i;
+
+ for (i = 0; i < pages; i++)
+ if (p[i].dirty)
+ free(p[i].data);
+
+ free(p);
+}
diff --git a/bootloader/mem.c b/bootloader/mem.c
new file mode 100644
index 0000000..3f6e564
--- /dev/null
+++ b/bootloader/mem.c
@@ -0,0 +1,69 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "bootloader.h"
+
+int
+transfer(int fd, FILE *dump, int ramend)
+{
+ int n;
+
+ put('D', fd);
+
+ printf("reading mem: ");
+
+ for (n = 0; n <= ramend; n++) {
+ twiddle();
+ fputc(get(fd), dump);
+ }
+ printf("\n");
+
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ char *dev = "/dev/ttyU0";
+ int c, fd;
+ FILE *dump;
+
+ while ((c = getopt(argc, argv, "f:")) != -1)
+ switch (c) {
+ case 'f':
+ dev = strdup(optarg);
+ break;
+ default:
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ dump = fopen("memdump", "w");
+ fd = open_tty(dev);
+ transfer(fd, dump, RAMEND);
+ close(fd);
+ fclose(dump);
+
+ return 0;
+}
diff --git a/bootloader/memdump/Makefile b/bootloader/memdump/Makefile
new file mode 100644
index 0000000..f958b94
--- /dev/null
+++ b/bootloader/memdump/Makefile
@@ -0,0 +1,7 @@
+# $Id$
+
+PROG= mem
+SRCS= mem.c tty.c
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/bootloader/tty.c b/bootloader/tty.c
new file mode 100644
index 0000000..8cf20fb
--- /dev/null
+++ b/bootloader/tty.c
@@ -0,0 +1,80 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <string.h>
+#include "bootloader.h"
+
+void
+put(unsigned char c, int fd)
+{
+ while (write(fd, &c, 1) == -1)
+ ;
+}
+
+unsigned char
+get(int fd)
+{
+ unsigned char c;
+
+ while (read(fd, &c, 1) == -1)
+ ;
+
+ return c;
+}
+
+void
+twiddle(void)
+{
+ static int pos;
+
+ putchar("|/-\\"[pos++ & 3]);
+ putchar('\b');
+}
+
+
+int
+open_tty(char *dev)
+{
+ struct termios tio;
+ int fd;
+
+ fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ if (fd < 0)
+ return -1;
+
+ fprintf(stderr, "open done, trying to set raw\n");
+
+ bzero(&tio, sizeof(tio));
+ tio.c_cflag = CS8 | CREAD | CLOCAL;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 10;
+ cfsetspeed(&tio, B9600);
+ cfmakeraw(&tio);
+ if (tcsetattr(fd, TCSANOW, &tio) < 0)
+ fprintf(stderr, "cannot set raw mode\n");
+
+ usleep(500);
+
+ return fd;
+}
diff --git a/firmware/Makefile b/firmware/Makefile
new file mode 100644
index 0000000..a65993e
--- /dev/null
+++ b/firmware/Makefile
@@ -0,0 +1,61 @@
+# $Id$
+
+PROG = firmware
+SRCS = firmware.c
+HEADERS =
+MCU_TARGET = atmega8
+F_CPU = 16000000
+PRESCALE = 8
+BAUD = 9600
+ORG = 0x1e00
+
+# You should not have to change anything below here.
+
+OBJS = ${SRCS:.c=.o}
+CC = avr-gcc
+CFLAGS = -Wall -Os -mmcu=${MCU_TARGET} \
+ -DF_CPU=${F_CPU} -DPRESCALE=${PRESCALE} -DBAUD=${BAUD}
+LDFLAGS = -Wl,-Map,${PROG}.map,--section-start=.text=${ORG}
+OBJCOPY = avr-objcopy
+OBJDUMP = avr-objdump
+SIZE = avr-size
+
+.SUFFIXES: .elf .lst .hex .bin .srec .ehex .ebin .esrec
+
+all: ${PROG}.elf ${PROG}.lst ${PROG}.hex ${PROG}.ehex size
+
+${SRCS}: ${HEADERS} Makefile
+
+${PROG}.elf: ${OBJS}
+ ${CC} ${CFLAGS} ${LDFLAGS} -o ${.TARGET} ${.ALLSRC}
+
+size: ${PROG}.elf
+ ${SIZE} -C --mcu=${MCU_TARGET} ${.ALLSRC}
+
+clean:
+ rm -f *.o ${PROG}.elf *.bak *.lst *.map *.hex *.bin *srec *.ehex *.ebin *.esrec
+
+.elf.lst:
+ ${OBJDUMP} -h -S ${.ALLSRC} > ${.TARGET}
+
+# Rules for building the .text rom images
+
+.elf.hex:
+ ${OBJCOPY} -j .text -j .data -O ihex ${.ALLSRC} ${.TARGET}
+
+.elf.bin:
+ ${OBJCOPY} -j .text -j .data -O binary ${.ALLSRC} ${.TARGET}
+
+.elf.srec:
+ ${OBJCOPY} -j .text -j .data -O srec ${.ALLSRC} ${.TARGET}
+
+# Rules for building the .eeprom rom images
+
+.elf.ehex:
+ ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O ihex ${.ALLSRC} ${.TARGET}
+
+.elf.ebin:
+ ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O binary ${.ALLSRC} ${.TARGET}
+
+.elf.esrec:
+ ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O srec ${.ALLSRC} ${.TARGET}
diff --git a/firmware/firmware.c b/firmware/firmware.c
new file mode 100644
index 0000000..a0a649b
--- /dev/null
+++ b/firmware/firmware.c
@@ -0,0 +1,104 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <avr/io.h>
+#include <util/setbaud.h> /* depends on BAUD & F_CPU env vars */
+#include <avr/boot.h>
+
+#define TIMEOUT (F_CPU >> 3) /* ca. 2 sec */
+
+union {
+ uint16_t word;
+ uint8_t byte[2];
+} data;
+
+void
+reboot()
+{
+ boot_rww_enable();
+ ((void(*)(void))0)(); /* jump to app */
+}
+
+void
+putch(char c)
+{
+ if (c == '\n')
+ putch('\r'); /* be unix polite */
+
+ loop_until_bit_is_set(UCSRA, UDRE);
+
+ UDR = c;
+}
+
+uint8_t
+getch(void)
+{
+ uint32_t counter = 0;
+
+ do {
+ if (++counter > TIMEOUT)
+ reboot();
+ } while (bit_is_clear(UCSRA, RXC));
+
+ return UDR;
+}
+
+int
+main(void)
+{
+ uint8_t i;
+ uint16_t off;
+
+ UCSRB = _BV(RXEN) | _BV(TXEN);
+ UBRRH = UBRRH_VALUE;
+ UBRRL = UBRRL_VALUE;
+ UCSRA &= ~_BV(U2X);
+
+ putch('+'); /* say hallo */
+
+ if (getch() != 'P') /* wait a while for program request */
+ reboot();
+ putch('p'); /* confirm */
+
+ for (;;) {
+ switch (getch()) {
+ case 'D': /* data request */
+ off = (uint16_t)getch() * SPM_PAGESIZE;
+ for (i = 0; i < SPM_PAGESIZE; i += 2) {
+ data.byte[0] = getch();
+ data.byte[1] = getch();
+ boot_page_fill(off + i, data.word);
+ }
+
+ boot_page_erase(off);
+ boot_spm_busy_wait();
+
+ boot_page_write(off);
+ boot_spm_busy_wait();
+
+ putch('d'); /* confirm */
+ break;
+ case 'R': /* reboot request */
+ reboot();
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/kernel/Makefile b/kernel/Makefile
new file mode 100644
index 0000000..1d5be25
--- /dev/null
+++ b/kernel/Makefile
@@ -0,0 +1,64 @@
+# $Id$
+
+PROG = kernel
+SRCS = kernel.c main.c uart.c heartbeat.c rgb.c hsv.c lcd3.c
+HEADERS = kernel.h stack.h
+MCU_TARGET = atmega8
+F_CPU = 16000000
+PRESCALE = 8
+STACK = 64
+TASKS = 8
+SEMAPHORES = 8
+BAUD = 9600
+
+# You should not have to change anything below here.
+
+CC = avr-gcc
+OBJCOPY = avr-objcopy
+OBJDUMP = avr-objdump
+SIZE = avr-size
+OBJS = ${SRCS:.c=.o}
+CFLAGS = -Wall -Os -mmcu=${MCU_TARGET} \
+ -DF_CPU=${F_CPU} -DPRESCALE=${PRESCALE} -DBAUD=${BAUD} \
+ -DSTACK=${STACK} -DTASKS=${TASKS} -DSEMAPHORES=${SEMAPHORES}
+LDFLAGS = -Wl,-Map,${PROG}.map
+
+.SUFFIXES: .elf .lst .hex .bin .srec .ehex .ebin .esrec
+
+all: ${PROG}.elf ${PROG}.lst ${PROG}.hex ${PROG}.ehex size
+
+${SRCS}: ${HEADERS} Makefile
+
+${PROG}.elf: ${OBJS}
+ ${CC} ${LDFLAGS} -o ${.TARGET} ${.ALLSRC}
+
+size: ${PROG}.elf
+ ${SIZE} -C --mcu=${MCU_TARGET} ${.ALLSRC}
+
+clean:
+ rm -f *.o ${PROG}.elf *.bak *.lst *.map *.hex *.bin *srec *.ehex *.ebin *.esrec
+
+.elf.lst:
+ ${OBJDUMP} -h -S ${.IMPSRC} > ${.TARGET}
+
+# Rules for building the .text rom images
+
+.elf.hex:
+ ${OBJCOPY} -j .text -j .data -O ihex ${.IMPSRC} ${.TARGET}
+
+.elf.bin:
+ ${OBJCOPY} -j .text -j .data -O binary ${.IMPSRC} ${.TARGET}
+
+.elf.srec:
+ ${OBJCOPY} -j .text -j .data -O srec ${.IMPSRC} ${.TARGET}
+
+# Rules for building the .eeprom rom images
+
+.elf.ehex:
+ ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O ihex ${.IMPSRC} ${.TARGET}
+
+.elf.ebin:
+ ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O binary ${.IMPSRC} ${.TARGET}
+
+.elf.esrec:
+ ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O srec ${.IMPSRC} ${.TARGET}
diff --git a/kernel/heartbeat.c b/kernel/heartbeat.c
new file mode 100644
index 0000000..6960e63
--- /dev/null
+++ b/kernel/heartbeat.c
@@ -0,0 +1,53 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <inttypes.h>
+#include <avr/io.h>
+#include "kernel.h"
+#include "tasks.h"
+
+#define PIN PB0
+
+void
+heartbeat(void *arg)
+{
+ /* 80bpm: 100ms on, 50ms off, 100ms on, 500ms off */
+ uint32_t d = deadline();
+ uint32_t r = release();
+
+ DDRB |= _BV(PIN);
+ PORTB &= ~_BV(PIN);
+
+ for (;;) {
+ PORTB ^= _BV(PIN);
+ r += MSEC(100);
+ update(r, d);
+
+ PORTB ^= _BV(PIN);
+ r += MSEC(50);
+ update(r, d);
+
+ PORTB ^= _BV(PIN);
+ r += MSEC(100);
+ update(r, d);
+
+ PORTB ^= _BV(PIN);
+ r += MSEC(500);
+ d = r + MSEC(750);
+ update(r, d);
+ }
+}
diff --git a/kernel/hsv.c b/kernel/hsv.c
new file mode 100644
index 0000000..f41bf09
--- /dev/null
+++ b/kernel/hsv.c
@@ -0,0 +1,25 @@
+/* $Id$ */
+/* public domain */
+
+#include <inttypes.h>
+
+void
+hsv(uint8_t *r, uint8_t *g, uint8_t *b, uint16_t h, uint8_t s, uint8_t v)
+{
+ uint8_t i, f, p, q, t;
+
+ i = h / 60;
+ f = h % 60;
+ p = v - ((uint16_t)v * s) / 255;
+ q = v - ((uint32_t)v * s * f) / (255 * 59);
+ t = v - ((uint32_t)v * s * (59 - f)) / (255 * 59);
+
+ switch (i % 6) {
+ case 0: *r = v; *g = t; *b = p; break;
+ case 1: *r = q; *g = v; *b = p; break;
+ case 2: *r = p; *g = v; *b = t; break;
+ case 3: *r = p; *g = q; *b = v; break;
+ case 4: *r = t; *g = p; *b = v; break;
+ case 5: *r = v; *g = p; *b = q; break;
+ }
+}
diff --git a/kernel/kernel.c b/kernel/kernel.c
new file mode 100644
index 0000000..1d37d97
--- /dev/null
+++ b/kernel/kernel.c
@@ -0,0 +1,297 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2010 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * based on TinyRealTime by Dan Henriksson and Anton Cervin
+ * http://www.control.lth.se/Publication/hen+04t.html
+ */
+
+#include <inttypes.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include "kernel.h"
+#include "stack.h"
+
+enum { TERMINATED, READYQ, TIMEQ, WAITQOFFSET };
+
+#define LO8(x) ((uint8_t)((uint16_t)(x)))
+#define HI8(x) ((uint8_t)((uint16_t)(x) >> 8))
+#define SCHEDULE TIMER1_COMPA_vect
+#define DISTANCE(from, to) ((int32_t)((to) - (from)))
+#define EPOCH 0x3FFFFFFFUL /* XXX */
+#define EPS (LATENCY / PRESCALE + 1) /* XXX */
+#define NOW(hi, lo) (((uint32_t)(hi) << 0x10) | (lo))
+
+struct task {
+ uint8_t spl;
+ uint8_t sph;
+ uint32_t release;
+ uint32_t deadline;
+ uint8_t state;
+};
+
+struct kernel {
+ struct task *running;
+ struct task *prev;
+ struct task *idle;
+ struct task *first;
+ struct task *last;
+ struct task task[TASKS + 1];
+ uint8_t semaphore[SEMAPHORES];
+ uint8_t *freemem;
+ uint16_t cycles;
+} kernel;
+
+ISR(SCHEDULE, ISR_NAKED)
+{
+ struct task *t;
+ struct task *rtr;
+ uint32_t now;
+ uint32_t nexthit;
+ int32_t timeleft;
+
+ PUSH_ALL();
+
+ TIMSK &= ~_BV(OCIE1A); /* turn off output compare 1A */
+
+ if (TIFR & _BV(TOV1)) {
+ TIFR |= _BV(TOV1); /* reset flag */
+ ++kernel.cycles;
+ }
+
+ now = NOW(kernel.cycles, TCNT1);
+ nexthit = now + EPOCH;
+
+ /* update idle task */
+ kernel.idle->release = now;
+ kernel.idle->deadline = nexthit;
+
+ rtr = kernel.idle;
+
+ for (t = kernel.first; t <= kernel.last; t++) {
+ /* release tasks from time-wait-queue */
+ if (t->state == TIMEQ) {
+ if (DISTANCE(now, t->release) < 0)
+ t->state = READYQ;
+ else if (DISTANCE(t->release, nexthit) > 0)
+ nexthit = t->release;
+ }
+
+ /* find next task to run */
+ if (t->state == READYQ && \
+ DISTANCE(t->deadline, rtr->deadline) > 0)
+ rtr = t;
+ }
+
+ if (kernel.running != rtr) {
+ /* switch task */
+ kernel.running->spl = SPL;
+ kernel.running->sph = SPH;
+ SPL = rtr->spl;
+ SPH = rtr->sph;
+ kernel.prev = kernel.running;
+ kernel.running = rtr;
+ }
+
+ now = NOW(kernel.cycles, TCNT1);
+ timeleft = DISTANCE(now, nexthit);
+
+ if (timeleft < EPS)
+ timeleft = EPS;
+
+ timeleft += TCNT1;
+
+ if (timeleft < 0xFFFF)
+ OCR1A = timeleft;
+ else if (TCNT1 < 0xFFFF - EPS)
+ OCR1A = 0;
+ else
+ OCR1A = EPS;
+
+ TIMSK |= _BV(OCIE1A);
+
+ POP_ALL();
+
+ reti();
+}
+
+void
+init(int idlestack)
+{
+ /* Set up timer 1 */
+ TCNT1 = 0; /* reset counter 1 */
+ TCCR1A = 0; /* normal operation */
+ TCCR1B = TIMER_FLAGS;
+ TIMSK = _BV(OCIE1A);
+
+ kernel.freemem = (void *)(RAMEND - idlestack);
+ kernel.idle = &kernel.task[0];
+ kernel.first = &kernel.task[1];
+ kernel.last = kernel.idle;
+ kernel.running = kernel.idle;
+ kernel.prev = kernel.idle;
+ kernel.cycles = 0;
+
+ /* Initialize idle task (task 0) */
+ kernel.running->release = 0;
+ kernel.running->deadline = EPOCH;
+
+ sei();
+}
+
+void
+task(void (*fun)(void *), uint16_t stack, uint32_t release, uint32_t deadline, void *args)
+{
+ struct task *t;
+ uint8_t *sp;
+ int i;
+
+ cli();
+
+ sp = kernel.freemem;
+ kernel.freemem -= stack;
+
+ /*
+ *sp-- = 'A';
+ *sp-- = 'A';
+ */
+
+ /* initialize stack */
+ *sp-- = LO8(fun); /* store PC(lo) */
+ *sp-- = HI8(fun); /* store PC(hi) */
+
+ for (i = 0; i < 25; i++)
+ *sp-- = 0; /* store r1-r0, SREG, r2-r23 */
+
+ /* Save args in r24-25 (input arguments stored in these registers) */
+ *sp-- = LO8(args);
+ *sp-- = HI8(args);
+
+ for (i = 0; i < 6; i++)
+ *sp-- = 0; /* store r26-r31 */
+
+ t = ++kernel.last;
+
+ t->release = release;
+ t->deadline = deadline;
+ t->state = TIMEQ;
+
+ t->spl = LO8(sp); /* store stack pointer */
+ t->sph = HI8(sp);
+
+ SCHEDULE();
+}
+
+void
+semaphore(uint8_t sema, uint8_t val)
+{
+ cli();
+
+ kernel.semaphore[sema] = val;
+
+ sei();
+}
+
+void
+wait(uint8_t sema)
+{
+ cli();
+
+ if (kernel.semaphore[sema] == 0) {
+ kernel.running->state = WAITQOFFSET + sema;
+ SCHEDULE();
+ } else
+ --kernel.semaphore[sema];
+
+ sei();
+}
+
+void
+signal(uint8_t sema)
+{
+ struct task *t;
+ struct task *rtr;
+
+ cli();
+
+ rtr = kernel.idle;
+
+ for (t = kernel.first; t <= kernel.last; t++) {
+ if (t->state == WAITQOFFSET + sema && \
+ DISTANCE(t->deadline, rtr->deadline) > 0)
+ rtr = t;
+ }
+
+ if (rtr != kernel.idle) {
+ rtr->state = READYQ;
+ SCHEDULE();
+ } else
+ ++kernel.semaphore[sema];
+
+ sei();
+}
+
+void
+update(uint32_t release, uint32_t deadline)
+{
+ cli();
+
+ kernel.running->state = TIMEQ;
+ kernel.running->release = release;
+ kernel.running->deadline = deadline > release ? deadline : release;
+
+ SCHEDULE();
+}
+
+uint32_t
+deadline(void)
+{
+ return kernel.running->deadline;
+}
+
+uint32_t
+release(void)
+{
+ return kernel.running->release;
+}
+
+uint32_t
+now(void)
+{
+ return NOW(kernel.cycles, TCNT1);
+}
+
+void
+suspend(void)
+{
+ cli();
+
+ kernel.running->state = TERMINATED;
+
+ SCHEDULE();
+}
+
+uint8_t
+running(void)
+{
+ return kernel.running - kernel.idle;
+}
+
+uint8_t
+previous(void)
+{
+ return kernel.prev - kernel.idle;
+}
diff --git a/kernel/kernel.h b/kernel/kernel.h
new file mode 100644
index 0000000..feab5b0
--- /dev/null
+++ b/kernel/kernel.h
@@ -0,0 +1,80 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2010 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __KERNEL_H
+#define __KERNEL_H
+
+#ifndef TASKS
+#warning "TASKS not set, fallback to default"
+#define TASKS 8
+#endif
+
+#ifndef SEMAPHORES
+#warning "SEMAPHORES not set, fallback to default"
+#define SEMAPHORES 8
+#endif
+
+#ifndef STACK
+#warning "STACK not set, fallback to default"
+#define STACK 64
+#endif
+
+#ifndef F_CPU
+#warning "F_CPU not set, fallback to default"
+#define F_CPU 1000000
+#endif
+
+#ifndef PRESCALE
+#warning "PRESCALE not set, fallback to default"
+#define PRESCALE 1
+#endif
+
+#if (PRESCALE == 1)
+#define TIMER_FLAGS _BV(CS10)
+#elif (PRESCALE == 8)
+#define TIMER_FLAGS _BV(CS11)
+#elif (PRESCALE == 64)
+#define TIMER_FLAGS (_BV(CS11) | _BV(CS10))
+#elif (PRESCALE == 256)
+#define TIMER_FLAGS _BV(CS12)
+#elif (PRESCALE == 1024)
+#define TIMER_FLAGS (_BV(CS12) | _BV(CS10))
+#else
+#warning "invalid PRESCALE value"
+#endif
+
+#define SEC(T) ((uint32_t)((T) * (F_CPU / PRESCALE)))
+#define MSEC(T) ((uint32_t)(T) * ((F_CPU / 1000) / PRESCALE))
+#define USEC(T) ((uint32_t)(T) * ((F_CPU / 1000000) / PRESCALE))
+
+void init(int idlestack);
+void task(void (*fun)(void *), uint16_t stacksize, uint32_t release, uint32_t deadline, void *args);
+void semaphore(uint8_t semnbr, uint8_t initVal);
+
+void wait(uint8_t semnbr);
+void signal(uint8_t semnbr);
+
+void update(uint32_t release, uint32_t deadline);
+void suspend(void);
+
+uint32_t now(void);
+uint32_t release(void);
+uint32_t deadline(void);
+uint8_t running(void);
+uint8_t previous(void);
+
+#endif
diff --git a/kernel/lcd3.c b/kernel/lcd3.c
new file mode 100644
index 0000000..7ad82aa
--- /dev/null
+++ b/kernel/lcd3.c
@@ -0,0 +1,184 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <inttypes.h>
+#include <avr/io.h>
+#include "kernel.h"
+#include "tasks.h"
+
+#define CLEAR_DISPLAY _BV(0)
+#define RETURN_HOME _BV(1)
+
+#define ENTRY_MODE_SET _BV(2)
+#define INC_DDRAM _BV(1)
+#define SHIFT_ENTIRE_DISP _BV(0)
+
+#define ON_OFF_CONTROL _BV(3)
+#define DISPLAY_ON _BV(2)
+#define CURSOR _BV(1)
+#define BLINK _BV(0)
+
+#define CURSOR_OR_DISPLAY_SHIFT _BV(4)
+#define SHIFT_CURS_LEFT (0x00 << 2)
+#define SHIFT_CURS_RIGHT (0x01 << 2)
+#define SHIFT_DISP_LEFT (0x10 << 2)
+#define SHIFT_DISP_RIGHT (0x11 << 2)
+
+#define FUNCTION_SET _BV(5)
+#define DATA_LENGTH_8BIT _BV(4) /* on 8 / off 4 bit */
+#define TWO_LINES _BV(3) /* on 2 / off 1 line */
+#define BIG_FONT _BV(2) /* on 5x10 / off 5x7 */
+
+
+#define SET_CGRAM_ADDRESS _BV(6)
+#define SET_DDRAM_ADDRESS _BV(7)
+#define BUSY_FLAG _BV(7)
+
+/* 3-wire interface with 74HC164 */
+#define PORT PORTD
+#define PORTDIR DDRD
+#define DATA PD5
+#define CLOCK PD6
+#define E PD7
+
+struct lcdargs {
+ uint32_t d;
+ uint32_t r;
+} lcdargs;
+
+#define snooze(t) do { lcdargs.r += USEC(t); update(lcdargs.r, lcdargs.d); } while (0)
+#define write_cmd(x, delay) do { write_byte((x), 0); snooze(delay); } while (0)
+#define write_data(x) do { write_byte((x), 1); snooze(43); } while (0)
+#define move(line, row) do { write_cmd(SET_DDRAM_ADDRESS | ((line) << 6) | (row), 39); } while (0)
+#define clear() do { write_cmd(CLEAR_DISPLAY, 1530); } while (0)
+#define home() do { write_cmd(RETURN_HOME, 1530); } while (0)
+
+
+/* recomended cycle 1us: 450ns on, 450ns off. this is beyond our resolution */
+#define wait_short() do { asm volatile ("nop"); } while (0)
+#define strobe(port, bit) do { port |= _BV(bit); wait_short(); port &= ~_BV(bit); } while (0)
+#define setif(cond, port, bit) do { if (cond) port |= _BV(bit); else port &= ~_BV(bit); } while (0)
+
+static void
+write_byte(uint8_t byte, uint8_t rs)
+{
+ uint8_t i;
+
+ for (i = 0; i < 8; i++) {
+ setif(byte & (0b10000000 >> i), PORT, DATA); /* MSF */
+ strobe(PORT, CLOCK);
+ }
+ setif(rs, PORT, DATA);
+ strobe(PORT, E);
+}
+
+static void
+mvputs(uint8_t line, uint8_t row, char *s)
+{
+ move(line, row);
+ while (*s)
+ write_data(*(s++));
+}
+
+static void
+mvputch(uint8_t line, uint8_t row, char ch)
+{
+ move(line, row);
+ write_data(ch);
+}
+
+static char *
+itoa(int32_t n)
+{
+ static char buf[12];
+ char *s = &buf[11];
+ uint32_t sign, u = n;
+
+ *s = '\0';
+
+ if ((sign = (n < 0)))
+ u = ~u + 1;
+
+ do
+ *--s = '0' + (u % 10);
+ while ((u /= 10) > 0);
+
+ if (sign)
+ *--s = '-';
+
+ while (s != buf)
+ *--s = ' ';
+
+ return s;
+}
+
+static char *
+itohex(uint32_t x)
+{
+ static char hex[] = "0123456789ABCDEF";
+ static char buf[9];
+ char *s = &buf[8];
+ uint8_t i;
+
+ *s = '\0';
+
+ for (i = 0; i < 32; i += 4)
+ *--s = hex[(x >> i) & 0x0f];
+
+ return s;
+}
+
+void
+lcd(void *arg)
+{
+ uint8_t i, t;
+
+ PORTDIR |= (_BV(DATA) | _BV(CLOCK) | _BV(E));
+
+ /* task init: wait >40ms */
+
+ lcdargs.d = deadline();
+ lcdargs.r = release();
+
+ /* 8 bit, 2 line, 5x8 font */
+ write_cmd(FUNCTION_SET | DATA_LENGTH_8BIT | TWO_LINES, 39);
+ /* no BUSY_FLAG until now */
+
+ /* display on, cursor off, cursor blink off */
+ write_cmd(ON_OFF_CONTROL | DISPLAY_ON, 39);
+
+ /* clear display */
+ clear();
+
+ /* entry mode */
+ write_cmd(ENTRY_MODE_SET | INC_DDRAM, 39);
+
+ mvputs(0, 0, "Task");
+ mvputs(1, 0, "Time");
+
+ for (;;) {
+ t = previous() - 1; /* 0 is idle */
+ for (i = 0; i < TASKS; i++)
+ mvputch(0, 5 + i, t == i ? '1' + t : '-');
+
+ mvputs(1, 5, itohex(now()));
+
+ lcdargs.r = lcdargs.d + MSEC(100);
+ lcdargs.d += MSEC(50);
+ update(lcdargs.r, lcdargs.d);
+ }
+}
diff --git a/kernel/main.c b/kernel/main.c
new file mode 100644
index 0000000..3a1921c
--- /dev/null
+++ b/kernel/main.c
@@ -0,0 +1,52 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <inttypes.h>
+#include <avr/io.h>
+#include "kernel.h"
+#include "tasks.h"
+
+uint8_t red, green, blue;
+
+struct rgbarg rgbargs[] = {
+ { &red, &green, &blue }
+};
+
+struct pwmarg pwmargs[] = {
+ { &red, PB2, 0, 0 },
+ { &green, PB3, 0, 0 },
+ { &blue, PB4, 0, 0 },
+};
+
+int
+main()
+{
+ init(STACK);
+
+ init_uart();
+
+ task(heartbeat, STACK, SEC(0), MSEC(10), 0);
+ task(rgb, STACK, SEC(0), MSEC(10), &rgbargs[0]);
+ task(pwm, STACK, SEC(0), MSEC(10), &pwmargs[0]);
+ task(pwm, STACK, SEC(0), MSEC(10), &pwmargs[1]);
+ task(pwm, STACK, SEC(0), MSEC(10), &pwmargs[2]);
+ task(lcd, STACK, MSEC(40), SEC(1), 0);
+
+ for (;;);
+
+ return 0;
+}
diff --git a/kernel/rgb.c b/kernel/rgb.c
new file mode 100644
index 0000000..c1aefde
--- /dev/null
+++ b/kernel/rgb.c
@@ -0,0 +1,79 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <inttypes.h>
+#include <avr/io.h>
+#include "kernel.h"
+#include "tasks.h"
+
+void hsv(uint8_t *, uint8_t *, uint8_t *, uint16_t, uint8_t, uint8_t);
+
+/*
+struct pwmarg pwmargs[] = {
+ { &red, PB2, 0, 0 },
+ { &green, PB3, 0, 0 },
+ { &blue, PB4, 0, 0 },
+};
+ */
+
+void
+rgb(void *arg)
+{
+ struct rgbarg *a = (struct rgbarg *)arg;
+ uint32_t d = deadline();
+ uint32_t r = release();
+ uint16_t i = 0;
+ uint8_t v;
+
+ for (;;) {
+ i = (i + 1) % 360;
+ v = i % 120;
+ v = (v < 60) ? 255 - 2 * v : 15 + 2 * v;
+
+ hsv(a->r, a->g, a->b, i, 255, v);
+
+ r = d + MSEC(28);
+ d = r + MSEC(2);
+ update(r, d);
+ }
+}
+
+void
+pwm(void *arg)
+{
+#define SCALE 4
+ struct pwmarg *a = (struct pwmarg *)arg;
+ a->d = deadline();
+ a->r = release();
+
+ DDRB |= _BV(a->pin);
+ PORTB &= ~_BV(a->pin);
+
+ for (;;) {
+ if (*a->value > 0) {
+ PORTB |= _BV(a->pin);
+ a->r = a->d += USEC(*a->value << SCALE);
+ update(a->r, a->d);
+ }
+
+ if (*a->value < 255) {
+ PORTB &= ~_BV(a->pin);
+ a->r = a->d += USEC((255 - *a->value) << SCALE);
+ update(a->r, a->d);
+ }
+ }
+}
diff --git a/kernel/stack.h b/kernel/stack.h
new file mode 100644
index 0000000..0f44954
--- /dev/null
+++ b/kernel/stack.h
@@ -0,0 +1,99 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2010 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __STACK_H
+#define __STACK_H
+
+/* average latency in cycles */
+#define LATENCY 72
+
+/* 68 cycles */
+#define PUSH_ALL() asm volatile ( \
+ "push r1 \n" \
+ "push r0 \n" \
+ "in r0, __SREG__ \n" \
+ "push r0 \n" \
+ "eor r1, r1 \n" \
+ "push r2 \n" \
+ "push r3 \n" \
+ "push r4 \n" \
+ "push r5 \n" \
+ "push r6 \n" \
+ "push r7 \n" \
+ "push r8 \n" \
+ "push r9 \n" \
+ "push r10 \n" \
+ "push r11 \n" \
+ "push r12 \n" \
+ "push r13 \n" \
+ "push r14 \n" \
+ "push r15 \n" \
+ "push r16 \n" \
+ "push r17 \n" \
+ "push r18 \n" \
+ "push r19 \n" \
+ "push r20 \n" \
+ "push r21 \n" \
+ "push r22 \n" \
+ "push r23 \n" \
+ "push r24 \n" \
+ "push r25 \n" \
+ "push r26 \n" \
+ "push r27 \n" \
+ "push r28 \n" \
+ "push r29 \n" \
+ "push r30 \n" \
+ "push r31 \n" )
+
+/* 69 cycles */
+#define POP_ALL() asm volatile ( \
+ "pop r31 \n" \
+ "pop r30 \n" \
+ "pop r29 \n" \
+ "pop r28 \n" \
+ "pop r27 \n" \
+ "pop r26 \n" \
+ "pop r25 \n" \
+ "pop r24 \n" \
+ "pop r23 \n" \
+ "pop r22 \n" \
+ "pop r21 \n" \
+ "pop r20 \n" \
+ "pop r19 \n" \
+ "pop r18 \n" \
+ "pop r17 \n" \
+ "pop r16 \n" \
+ "pop r15 \n" \
+ "pop r14 \n" \
+ "pop r13 \n" \
+ "pop r12 \n" \
+ "pop r11 \n" \
+ "pop r10 \n" \
+ "pop r9 \n" \
+ "pop r8 \n" \
+ "pop r7 \n" \
+ "pop r6 \n" \
+ "pop r5 \n" \
+ "pop r4 \n" \
+ "pop r3 \n" \
+ "pop r2 \n" \
+ "pop r0 \n" \
+ "out __SREG__, r0 \n" \
+ "pop r0 \n" \
+ "pop r1 \n" )
+
+#endif
diff --git a/kernel/tasks.h b/kernel/tasks.h
new file mode 100644
index 0000000..aa7f992
--- /dev/null
+++ b/kernel/tasks.h
@@ -0,0 +1,39 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __TASKS_H
+#define __TASKS_H
+
+struct rgbarg {
+ uint8_t *r, *g, *b;
+};
+
+struct pwmarg {
+ uint8_t *value;
+ uint8_t pin;
+ uint32_t d;
+ uint32_t r;
+};
+
+void init_uart(void);
+
+void heartbeat(void *);
+void rgb(void *);
+void pwm(void *);
+void lcd(void *);
+
+#endif
diff --git a/kernel/uart.c b/kernel/uart.c
new file mode 100644
index 0000000..63f5c11
--- /dev/null
+++ b/kernel/uart.c
@@ -0,0 +1,80 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2011 Dimitri Sokolyuk <demon@dim13.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BAUD
+#warning "BAUD not set, fallback to default"
+#define BAUD 9600
+#endif
+
+#include <inttypes.h>
+#include <avr/io.h>
+#include <avr/wdt.h>
+#include <avr/interrupt.h>
+#include <util/setbaud.h>
+#include "kernel.h"
+#include "tasks.h"
+
+void
+uart_putchar(char c)
+{
+ loop_until_bit_is_set(UCSRA, UDRE);
+ UDR = c;
+}
+
+ISR(SIG_UART_RECV)
+{
+ uint8_t c = UDR;
+ uint8_t *p = 0;
+
+ switch (c) {
+ case 'R': /* reboot */
+ wdt_enable(WDTO_15MS);
+ break;
+ case 'D': /* dump */
+ while (p <= (uint8_t *)RAMEND)
+ uart_putchar(*p++);
+ break;
+ case 'T':
+ UCSRB |= _BV(UDRIE);
+ break;
+ case 't':
+ UCSRB &= ~_BV(UDRIE);
+ break;
+ case '\r':
+ case '\n':
+ break;
+ default:
+ uart_putchar('?');
+ break;
+ }
+}
+
+ISR(SIG_UART_DATA)
+{
+ uint8_t r = running();
+
+ UDR = r ? '0' + r : '.';
+}
+
+void
+init_uart(void)
+{
+ UCSRB = _BV(RXCIE) | _BV(RXEN) | _BV(TXEN);
+ UBRRH = UBRRH_VALUE;
+ UBRRL = UBRRL_VALUE;
+ UCSRA &= ~_BV(U2X);
+}