Working switch2led demonstration on tic55x
authorRick van Rein <vanrein@hwdev.(none)>
Wed, 6 Apr 2011 09:37:53 +0000 (09:37 +0000)
committerRick van Rein <vanrein@hwdev.(none)>
Wed, 6 Apr 2011 09:37:53 +0000 (09:37 +0000)
This is a first release that is starting to work on real
phone hardware: Grandstream BT200.  The part that works
is the backlight to the LCD and the hook contact, but
that at least shows control.  Work has been done on the
timer actions, but that has not been made to work yet,
at least not based on interrupts.

51 files changed:
Makefile
TODO
bin/i2cp/Makefile [new file with mode: 0644]
bin/i2cp/i2cp [new file with mode: 0755]
bin/i2cp/i2cp.c [new file with mode: 0644]
doc/porting.rst [new file with mode: 0644]
doc/top2bottom.rst
include/0cpm/led.h
include/0cpm/netcmd.h
include/0cpm/netfun.h
include/0cpm/timer.h
include/bottom/grandstream.h [new file with mode: 0644]
include/bottom/linuxtuntest.h [new file with mode: 0644]
include/bottom/tic55x.h [new file with mode: 0644]
include/stdbool.h [new file with mode: 0644]
src/README [new file with mode: 0644]
src/driver/Makefile
src/driver/tic55x/gpio.c [new file with mode: 0644]
src/driver/tic55x/grandstream-bt20x.c [new file with mode: 0644]
src/driver/tic55x/int.c [new file with mode: 0644]
src/driver/tic55x/isrmap.asm [new file with mode: 0644]
src/driver/tic55x/timer.c [new file with mode: 0644]
src/driver/util/ledsimu.c [new file with mode: 0644]
src/driver/util/linuxtuntest.c
src/function/Kconfig [new file with mode: 0644]
src/function/Kconfig.devel [new file with mode: 0644]
src/function/Makefile [new file with mode: 0644]
src/function/bootloader/main.c [new file with mode: 0644]
src/function/develtest/keys2display.c [new file with mode: 0644]
src/function/develtest/netconsole.c [new file with mode: 0644]
src/function/develtest/switch2led.c [new file with mode: 0644]
src/function/develtest/timer2led.c [new file with mode: 0644]
src/function/sip6phone/topmain.c [new file with mode: 0644]
src/kernel/cpu.c
src/net/core.c
src/net/input.c
src/net/reply.c
src/net/send.c
src/phone/app_zero.c
src/target/Kconfig
src/target/Kconfig.brand [new file with mode: 0644]
src/target/Kconfig.gigaset [new file with mode: 0644]
src/target/Kconfig.grandstream [new file with mode: 0644]
src/target/Kconfig.meta [new file with mode: 0644]
src/target/Kconfig.model [new file with mode: 0644]
src/target/Kconfig.platform [new file with mode: 0644]
src/target/Kconfig.posix [new file with mode: 0644]
src/target/Kconfig.smc [new file with mode: 0644]
src/target/Makefile
src/target/linksys_spa962.h
src/target/smc_dsp20x.h [new file with mode: 0644]

index 45dda2d..84f9edb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -33,15 +33,18 @@ include src/net/Makefile
 include src/phone/Makefile
 
 include src/target/Makefile
+include src/function/Makefile
 include src/driver/Makefile
 
+BINPATH = $(CONFIG_PLATFORM_BIN_PATH):$(PATH)
+
 #
 # Dependencies for generated include files
 # TODO: Solve cyclic dependencies on non-generated file
 #
 include/config.h: .config
-       ( cat $< ; for m in $(metavars-y) ; do echo $$m ; done ) | sed -e '/^#/d' -e 's/^\([A-Z0-9_]*\)=\(.*\)/#define \1 \2/'  > $@
-       for i in $(includes-y) ; do echo "#include \"../$$i\"" >> $@ ; done
+       ( cat $< ; for m in $(metavars-y) ; do echo $$m ; done ) | sed -e '/^#/d' -e 's/^\([A-Za-z0-9_]*\)=\(.*\)/#define \1 \2/'  > $@
+       for i in $(includes-y) ; do echo "#include <$$i>" >> $@ ; done
 
 .PHONY += configincludes
 configincludes: include/config.h
@@ -64,54 +67,40 @@ configincludes: include/config.h
 # rule is that all API calls between the two halves must be
 # documented in doc/top2bottom.*
 #
-bin/firmerware.bin: bin/firmerware.elf
-       strip -s -o $@ $<
-
-bin/firmerware.elf: bin/top.o bin/bottom.o
-       gcc -MD -o $@ bin/top.o bin/bottom.o
-       @echo
-       @echo "*** Compilation succesful"
-       @echo
-       @size bin/firmerware.elf
 
 bin/top-kernel.o: $(objs-top-kernel-y)
-       ld -r -o $@ $(objs-top-kernel-y)
+       PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-top-kernel-y)
 
 bin/top-net.o: $(objs-top-net-y)
-       ld -r -o $@ $(objs-top-net-y)
+       PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-top-net-y)
 
 bin/top-phone.o: $(objs-top-phone-y)
-       ld -r -o $@ $(objs-top-phone-y)
+       PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-top-phone-y)
 
-bin/top.o: bin/top-kernel.o bin/top-net.o bin/top-phone.o
-       ld -r -o $@ bin/top-kernel.o bin/top-net.o bin/top-phone.o
+# bin/top.o: bin/top-kernel.o bin/top-net.o bin/top-phone.o
+#      $(LD) $(LDFLAGS) -r -o $@ bin/top-kernel.o bin/top-net.o bin/top-phone.o
+bin/top.o: $(objs-top-y)
+       PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-top-y)
 
 bin/bottom.o: $(objs-bottom-y)
-       ld -r -o $@ $(objs-bottom-y)
-
-#
-# General compiler rule
-# TODO: Use -Wall and remove silencing-up overrides
-# gcc -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -fno-builtin -MD -c -Iinclude -ggdb3 -o $@ $<
-#
-%.o: %.c
-       gcc -fno-builtin -MD -c -Iinclude -ggdb3 -o $@ $<
+       PATH=$(BINPATH) $(LD) $(LDFLAGS) -r -o $@ $(objs-bottom-y)
 
 #
 # Create a "tags" file for easy Vim navigation
 #
-tags:
+tags: src/net/6bed4.c
        ctags $(objs-top-kernel-y:.o=.c) $(objs-top-net-y:.o=.c) $(objs-top-phone-y:.o=.c) $(objs-bottom-y:.o=.c) include/0cpm/*.h include/config.h
 
 .PHONY += clean
 clean:
-       rm -f $(objs-top-kernel-y)
-       rm -f $(objs-top-net-y)
-       rm -f $(objs-top-phone-y)
+       rm -f $(objs-top-y) $(objs-top-n) $(objs-top-)
+       # rm -f $(objs-top-net-y)
+       # rm -f $(objs-top-phone-y)
        rm -f $(objs-bottom-y)
-       rm -f $(objs-top-kernel-y:.o=.d)
-       rm -f $(objs-top-net-y:.o=.d)
-       rm -f $(objs-top-phone-y:.o=.d)
+       rm -f $(objs-top-y:.o=.d) $(objs-top-n:.o=.d) $(objs-top-:.o=.d)
+       # rm -f $(objs-top-kernel-y:.o=.d)
+       # rm -f $(objs-top-net-y:.o=.d)
+       # rm -f $(objs-top-phone-y:.o=.d)
        rm -f $(objs-bottom-y:.o=.d)
        rm -f bin/top-kernel.o bin/top-net.o bin/top-phone.o
        rm -f bin/top.o bin/bottom.o
diff --git a/TODO b/TODO
index 55bc665..ae699f6 100644 (file)
--- a/TODO
+++ b/TODO
@@ -12,23 +12,6 @@ The current code contains a few things that may or may not be so good
 in the end.  After gaining some experience, it is good to have a good
 look at:
 
-* Pointers are cast back and forth to uint32_t values.  This makes the
-  code unsuitable for 64-bit architectures and, much more of a problem,
-  for 16-bit architectures such as 16-bit digital signal processors.
-
-* Parsing and checksumming is not sufficiently paranoid.  The current
-  netinput code assumes proper behaviour from its networking partners.
-  That is not a proper assumption for an internetworking device :-)
-  Specifically, no effort has been done to check the packet size where
-  indices and offsets are applied.  Before this is handled, the code
-  MUST NOT be released as anything but alpha.
-
-* The use of BPF-style commands in netinput.c -- it can be made fairly
-  compact if matched up with machine commands, but is it really more
-  efficient than an optimising C compiler?  If the difference is
-  negligable, then this code should go, even if it brings advantages
-  on some platforms.  The style is then simply "too inventive".
-
 * The mem[] array is untyped, calling for lots of cast commands.  This
   is not handy, and a result of the BPF-style architecture for netinput.
   (The original idea was to do the entire processing in that style, but
diff --git a/bin/i2cp/Makefile b/bin/i2cp/Makefile
new file mode 100644 (file)
index 0000000..95a5feb
--- /dev/null
@@ -0,0 +1,2 @@
+i2cp: i2cp.c
+       gcc -o i2cp i2cp.c
diff --git a/bin/i2cp/i2cp b/bin/i2cp/i2cp
new file mode 100755 (executable)
index 0000000..7a703f6
Binary files /dev/null and b/bin/i2cp/i2cp differ
diff --git a/bin/i2cp/i2cp.c b/bin/i2cp/i2cp.c
new file mode 100644 (file)
index 0000000..bd30dfd
--- /dev/null
@@ -0,0 +1,127 @@
+/* i2cp.c -- EEPROM read/write over i2c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <linux/i2c-dev.h>
+
+
+#define INTERPAGE_WAIT_MS 5
+#define PAGESIZE_BYTES 128
+
+
+int main (int argc, char *argv []) {
+
+       uint32_t size = ~0L;
+       uint32_t address = 0;
+
+       if (argc != 3) {
+               fprintf (stderr, "Usage: %s image.bin /dev/i2c-N\n   or: %s /dev/i2c-N image.bin\n", argv [0], argv [0]);
+               exit (1);
+       }
+       
+       struct stat stin;
+       if (stat (argv [1], &stin) == -1) {
+               perror ("Failed to stat input");
+               exit (1);
+       }
+       if (stin.st_rdev == 0) {
+               if (stin.st_size >= 8 * 65536) {
+                       fprintf (stderr, "Input image exceeds maximum possible\n");
+                       exit (1);
+               } else {
+                       size = stin.st_size;
+               }
+       }
+
+       struct stat stout;
+       if (stat (argv [2], &stout) == -1) {
+               perror ("Failed to stat output");
+               exit (1);
+       }
+       if (stout.st_rdev == 0) {
+               if (stout.st_size >= 8 * 65536) {
+                       fprintf (stderr, "Output image exceeds maximum possible\n");
+                       exit (1);
+               } else if (size == (uint32_t) ~0L) {
+                       size = stout.st_size;
+               }
+       }
+
+
+       int fin = open (argv [1], O_RDWR);
+       if (fin < 0) {
+               perror ("Failed to read input");
+               exit (1);
+       }
+       int fout = open (argv [2], O_RDWR);
+       if (fout < 0) {
+               perror ("Failed to access output");
+               exit (1);
+       }
+
+       if (stin.st_rdev) {
+               ioctl (fin, I2C_TIMEOUT, 1);
+               ioctl (fin, I2C_RETRIES, 2);
+       }
+       if (stout.st_rdev) {
+               ioctl (fout, I2C_TIMEOUT, 1);
+               ioctl (fout, I2C_RETRIES, 2);
+       }
+
+       while (address < size) {
+               uint8_t buf [2 + PAGESIZE_BYTES];
+               buf [0] = (address & 0x0000ff00) >> 8;
+               buf [1] = (address & 0x000000ff);
+               if ((address & 0x0000ffff) == 0x000000) {
+                       uint8_t slave = address >> 16;
+                       slave &= 0x07;
+                       slave += 0x50;
+                       if (stin.st_rdev) {
+                               if (ioctl (fin, I2C_SLAVE, slave) == -1) {
+                                       perror ("Failed to set input slave address");
+                                       exit (1);
+                               }
+                       }
+                       if (stout.st_rdev) {
+                               if (ioctl (fout, I2C_SLAVE, slave) == -1) {
+                                       perror ("Failed to set output slave address");
+                                       exit (1);
+                               }
+                       }
+               }
+               if (stin.st_rdev) {
+                       write (fin, buf, 2);
+               }
+               int rdlen = read (fin, buf+2, (size-address) >= PAGESIZE_BYTES? PAGESIZE_BYTES: size-address);
+               if (rdlen >= 0) {
+                       if (rdlen == 0) {
+                               break;
+                       }
+                       if (stout.st_rdev) {
+                               if (write (fout, buf, 2 + rdlen) < 2 + rdlen) {
+                                       perror ("Failed to write to i2c");
+                               }
+                       } else {
+                               if (write (fout, buf+2, rdlen) < rdlen) {
+                                       perror ("Failed to write to file");
+                               }
+                       }
+               } else {
+                       perror ("Failed to read");
+                       exit (1);
+               }
+               address += rdlen;
+               usleep (INTERPAGE_WAIT_MS * 1000);
+       }
+
+       close (fin);
+       close (fout);
+       return 0;
+}
diff --git a/doc/porting.rst b/doc/porting.rst
new file mode 100644 (file)
index 0000000..1ea0769
--- /dev/null
@@ -0,0 +1,471 @@
+======================================
+Porting 0cpm Firmerware to a new Phone
+======================================
+
+.. contents::
+
+This manual describes the steps to port the 0cpm Firmerware to
+a new phone.
+
+
+Notes for hardware manufacturers
+================================
+
+**Welcome!**
+We are delighted about any hardware manufacturer who chooses
+to use this firmware on their own phones.  We believe that the
+best of worlds comes from dedicated hardware manufacturers who
+use firmware from dedicated software manufacturers.  We also
+believe that open source gives a great economic boost, as it
+enables sharing between parties that would not usually work
+together.  But as things go, this is a two-sided story; this
+software is not only grab-and-run, but it also obliges you to
+share back with the community.  In the end, your skills at
+hardware design and marketing are what will set you apart.
+
+**License:**
+Please read the ``LICENSE`` file carefully.  Using this software,
+or even parts of it, makes it apply to you and your work.
+The obligations imposed by the license are all related to keeping
+your firmware open and modifiable to its users:
+
+* you must supply source code in all versions sold
+* you must include a toolchain for building the code
+* you must inform your users about all this
+
+We are quite willing to include your source code changes into the
+main repository for this project, as long as you are mindful about
+the structure of the project; specifically, the separation between
+top and bottom halves is vital.  The top half is for generic logic
+and the bottom half is for driving the actual hardware; these should
+never be mixed and a generic (but possibly evolving) API should be
+used between the two layers.
+
+**Functions:**
+Note that this firmware can do more than just support SIP
+telephony.  It can be built to fulfil functions that are very
+useful to various applications:
+
+* SIP phone, simulating analog phones plus *much* more
+* SIP doorbell, a hotline phone that dials out as soon as it is switched on
+* SIP alarm clock, answering wakeup calls and playing their sounds
+* bootloader, a small tool to access the flash over TFTP
+* development/test functions to test drivers one by one
+
+The responsibilities from the license only apply to the portions
+of the firmware that you are using; for instance, you could use
+the bootloader from this project with your own non-phone application
+and only have to release source code and access to the bootloader.
+
+
+Notes for organisations using phones
+====================================
+
+Phones usually represent quite a bit of value to companies using
+them, so it is not optimal to discard them solely on account of
+their firmware.  This project defines new firmware, and aims it
+to run on as many platforms as possible.
+
+If you are interested in reusing your phone with modern, free
+software, you could consider finding a hacker or nerd to reverse
+engineer the phone, and put in this newer firmware.  If successful,
+the phones can be tweaked to do exactly what they are supposed to
+do, by simply changing the firmware and uploading it to all
+phones in use.
+
+The process of reverse engineering is difficult, and not all the
+required information is available for all phones, so it may not
+be possible in general.  If you decide to walk this path, you
+probably should invest a little in analysing whether it is
+possible at all before taking the plunge and handing out the
+assignment to actually reverse-engineer your phones.
+
+As such changes and modifications would be sold to you, all
+results from the project would be donated back to this project.
+This means that you will be doing many people a favour, and that
+need not be an anonymous act either!
+
+
+Materials needed
+================
+
+Make sure you have a reasonable kit of electronics equipment
+on hand:
+
+* screwdrivers, pliers
+* multimeter that beeps if it finds a contact
+* glass scraper with a handle
+* soldering iron and related tools
+* wires, jumpers, access to all sorts of electronics parts
+* Linux PC (Windows might work as a sub-optimal substitute)
+* useful if available: oscilloscope, logic analyser
+
+The multimeter should be sensitive enough to measure through
+a device without damaging it.  Its beep is very helpful because
+it allows you to drag one pin over the many pins of a large chip
+to find the connection to another point in the circuit.
+
+
+Understanding your hardware
+===========================
+
+This section is mainly of interest to reverse engineers.
+
+
+Identifying devices
+-------------------
+
+Some manufacturers "protect" the identity of a chip with a layer
+of paint.  That is a good sign; it probably means that the chip
+is generic, and good documentation and toolchains may well be
+available for it.
+
+Paint on chips can be scraped off with a glass scraper.  Look for
+one with a handle to give you more control.  Use the flat surface
+of the chip and drive the scraper through, almost as if you are
+removing snow from a sidewalk.  It may take you some practice to
+really get handy doing this; just remember to err on the safe side
+as your could also cut into the chip with the scraper.
+
+The elements usually found in a phone are:
+
+* A major chip, usually a system-on-chip (SoC) which embeds a
+  processor with timers, I/O pin drivers, serial ports and so on.
+
+  Although a family of devices usually sticks to a particular SoC,
+  it seems that every manufacturer has their own.  Silly but true.
+
+* An ethernet chip.  If the phone has two external LAN connectors,
+  it will also include a switch.  Depending on the phone, it may
+  hold two ethernet interfaces (which is rare and silly), one
+  ethernet interface and a switch, or a combination of those.
+
+  By far the most common chip used is an RTL8019AS.  Since this is
+  a 10 Mb/s device, it is usually combined with a 100 Mb/s switch
+  so the outside connectors are faster.
+
+* RAM chip(s).  These used to be static RAM but even here the DRAM
+  chips are taking over.  These are silly chips, because they are
+  the only type of memory that suffers from amnesia; still, they
+  are the most compact and usually offer more bits on an area.
+
+* Flash chip(s).  These come in NAND and NOR flavours, referring to
+  block- and byte-addressed varieties, respectively.  The NOR flash
+  is common, because it enables running programs straight from the
+  flash memory.  For that reason, they commonly use 70 ns chips.
+
+* A codec chip.  These are a bit like embedded sound cards; they can
+  be accessed over a protocol like SPI to interact with microphones,
+  speakers and so on.  They usually include analog electronics such
+  as amplifiers.
+
+Don't forget to check the PCB's bottom; there may be components on
+both sides!
+
+
+Fetch documentation
+-------------------
+
+Given that all devices on the board are identified, lookup their
+documentation.  A web search with the serial numbers on the chips
+usually does wonders, although these search terms are also being
+used to attract people wanting to purchase them to trading sites.
+Adding a term like GND or Vcc may help.
+
+If you cannot find all documentation for forward engineering, it
+may become difficult to port to this platform.  You could try
+contacting the vendor of the chips for information, but only if
+they haven't published it online.  Most hardware vendors are
+keen on seeing open source projects develop around their chips.
+
+You may be able to locate drivers for peripheral chips in kernels
+like Linux' -- this may actually help you to drivers for such
+chips that were obtained by reverse engineering such chips when
+they were used in PCs.  The hardware used in phones is not nearly
+as modern as that used in PCs so the odds to this are good.
+
+Save everything found in a ``datasheet`` directory for your porting
+project; you will want to refer to it very often, and you don't want
+to have to repeat your search.  Also, it will be easier to share
+what you found if you store it like that.
+
+
+Find a toolchain
+----------------
+
+Based on the SoC chip used, look for a toolchain.  The documentation
+will probably tell you what kind of processor is embedded, and you
+may find an open source toolchain (like gcc_, llvm_, gas) or one
+provided by the hardware manufacturer.
+
+You really could confront the hardware vendor with it if you wanted
+to use their platform compiler for an open source project.  Most
+like open source, and have used it for long as consumers; they may
+also see the advantage of their hardware being supported by an open
+source phone application, especially if they realise that competitors
+do have support for it.  VoIP is currently a cut-throat market.
+
+.. _gcc : http://gcc.gnu.org/install/specific.html
+
+.. _gas : http://sourceware.org/binutils/docs/as/index.html
+
+.. _llvm : http://llvm.org/
+
+
+
+Gaining control
+===============
+
+Most chips provide a number of ways through which you can gain control.
+Most circuit boards will actually have jumper positions for soldering-on
+a connector that can hold such controls.
+
+Study the chip documentation for the SoC at hand for ways of getting in,
+and see if those are wired to the jumper positions on your board.
+Various forms of access exist in practice.
+
+
+Serial
+------
+
+Serial interfaces usually have 3 or 4 pins; GND, RxD, TxD and
+sometimes an extra Vcc pin.  The level of these interfaces is
+usually 3V3, so you will need a converter for this; you could
+use a cable intended for a suitable phone (I use one suitable
+for Siemens MC60 phones).
+
+If you do this a lot, you will like to have an
+`autobaud interface`_ to the RS-232 port.
+
+.. _`autobaud interface` : http://spritesmods.com/?art=autobaud&page=1
+
+Once attached, you want to try using an application like
+``minicom`` to figure out the baudrate and see if a proper
+console pops up.  It may give you good information about the
+kind of device that is running on the phone.  It may even
+give you a root prompt.
+
+Look for bootloaders; if you are lucky, you will be using an
+openly documented bootloader that explains how to install new
+firmware after something like a TFTP download.
+
+A question to always ask yourself is how users could do such things
+without soldering.  Is there a webbed interface that lets you do
+the same as the serial bootloader?  It may be worth to try to save
+the current firmware first, so you can go back and test such things.
+
+
+JTAG
+----
+
+JTAG access is ideal if you can get it; it will give you direct
+control over the bus, so you can probe keys and see on your PC
+what it does to your bus, and you could steer selected pins to
+see if and how they influence LEDs and the display.  Most
+importantly though, it could let you upload and download flash
+contents without *any* support from the chip.  In other words,
+once you have JTAG working, you have full control over your phone.
+
+The Joint Testing Action Group defined an interface named JTAG_
+which clocks bits in and out of a chip; these bits can represent
+internal state, but the only standardised part reflects on the
+external pins of a chip.  A so-called `boundary scan`_ meanst that
+these new external pin values are clocked in while the old ones
+are being clocked out, one by one in a sequence.
+
+.. _JTAG : http://en.wikipedia.org/wiki/Jtag
+
+.. _`boundary scan` : http://en.wikipedia.org/wiki/Boundary_scan
+
+The boundary scan interface is specified in a special file that
+is usually available from SoC manufacturers; look for BSDL or
+BSD downloads.
+
+Tools like UrJTAG_ and OpenOCD_ can help with these boundary
+scans, although JTAG often involves tweaking and takes some
+keen attention.  But once you got it working, you should be
+ready to go.
+
+Of the two tools, UrJTAG is older and not as actively developed
+as OpenOCD is.  OpenOCD has a very clear structure, making it
+very easy to work on; but it cannot currently process BSDL
+yet (I am working on that, as a matter of fact) which is possible
+with UrJTAG.  One problem with BSDL is that the syntax is not
+public (sigh!) so parsers, as is the case with UrJTAG, may not
+successfully process all BSDL files around.
+
+.. _UrJTAG : http://urjtag.org/
+
+.. _OpenOCD : http://openocd.berlios.de/web/
+
+
+Bootloader
+----------
+
+Some chips have built-in bootloaders that can download code over
+a more-or-less standard interface, like serial, I2C or SPI.  This
+may take a bit of soldering, but it is actually a very good way
+to control your device because it does not need to replace the
+contents of your phone's flash memory.
+
+Depending on the bootloader, you would need to setup a suitable
+access for code from your PC to the booting device.  For instance,
+Texas Instruments' TMS320VC55xx devices can boot from I2C EEPROMs
+attached to the right pins; you could setup an interface to match
+Linux' ``i2c-parport`` interface as documented in the
+``Documentation/i2c/busses/i2c-parport`` file in the kernel sources.
+
+
+Vendor-specific
+---------------
+
+Vendors sometimes develop their own connectors for development and
+debugging.  Although these certaintly give a lot of control, some
+are very expensive.  Usually, cheaper alternatives are available
+if you have enough determination.
+
+
+
+Mapping your hardware
+=====================
+
+You should figure out how all the buttons, LEDs and LCD connections
+are wired in your phone.  It is not important to know each resistor
+and capacitor in the path, but be aware that your multimeter may not
+beep if it finds a connection through a buffering resistor.  Also,
+you may have to figure out how to measure through driving transistors.
+
+Even if you need to be mindful of such analog helper components,
+what you are looking for is a map of the logic connections between
+your SoC and the I/O facilities of your phone.  This may involve
+flipflops selected by certain addresses, a scanning matrix for the
+keyboard, and so on.
+
+You will also want to find out how the chip-select lines of the
+various chips on your board are triggered.  This will help to
+establish where Flash, RAM and so on are located in the memory
+map of your SoC.
+
+Finally, find out how the codec and/or the microphones and speakers
+are driven.  This will determine how you should drive sound.
+
+
+Actually porting the 0cpm firmerware
+====================================
+
+Creating a port of the firmware should take minimal effort; that is,
+all that was possible to guide you in a generic sense has been done
+in the firmerware.
+
+Save all the binary intermediate results if they work, as well as any
+intermediate forms such as ELF or COFF files and source; if everything
+breaks down it is good to be able to reconstruct earlier results and
+decide whether the problem is related to hardware or your firmware.
+This could have stopped me from going insane, if only I had realised
+it in time ``;-)``
+
+
+Extend the configuration
+------------------------
+
+TODO
+
+
+Build 1: Basic I/O
+------------------
+
+In ``make menuconfig``, select the firmware function ``Test switch / light``
+that will toggle the message light that is usually present on phones
+in response to the hook contact.
+
+To build this, you would normally have to write simple I/O facilities.
+You would need to read the hook contact to implement
+``bottom_phone_is_offhook()`` and you would need to output a bit for
+``bottom_led_set()``.  If you care to play with it, update the file
+``src/function/develtest/switch2led.c`` but be sure to recover the original
+before you submit your owrk.
+
+If this works, you know that you have full control over the device,
+and that you have a working toolchain going all the way into the
+phone. *Congratulations!*
+
+
+Build 2: Timers and interrupts
+------------------------------
+
+In ``make menuconfig``, select the firmware function ``Test timer interrupts``
+that will setup a timer and respond to interrupts every 0,5 second by
+togging the message LED.
+
+To build this, you would normally have to write a timer setup and
+interrupt service routine to handle ``bottom_time()`` and
+``bottom_set_timer_set()`` --do not forget to return the old setting for
+the latter-- in addition to the previously written ``bottom_led_set()``
+function.  If you care to play with it, edit
+``src/function/develtest/timer2led.c`` but be sure to recover the original
+before you submit your work.
+
+If this works, you are handling interrupts and you can do time calculations
+as well as setup timers.  The complexities of timer queues and interrupt
+handling is further arranged in the top half.
+
+
+Build 3: Keys and display
+-------------------------
+
+In ``make menuconfig``, select the firmware function ``Test keyboard / display``
+that will scan the keyboard and write its findings to the display.
+
+TODO: To build this, you would normally have to write a timer setup and
+interrupt service routine to handle ``bottom_time()`` and
+``bottom_set_timer_set()`` --do not forget to return the old setting for
+the latter-- in addition to the previously written ``bottom_led_set()``
+function.  If you care to play with it, edit
+``src/function/develtest/keys2display.c`` but be sure to recover the original
+before you submit your work.
+
+If this works, you are able to scan keys and write texts on the display.
+
+
+Build 4: Networked console
+--------------------------
+
+In ``make menuconfig``, select the firmware function ``Test network``
+that will provide an LLC-based console over ethernet.
+
+TODO: To build this, you would normally have to write a timer setup and
+interrupt service routine to handle ``bottom_time()`` and
+``bottom_set_timer_set()`` --do not forget to return the old setting for
+the latter-- in addition to the previously written ``bottom_led_set()``
+function.  If you care to play with it, edit
+``src/function/develtest/keys2display.c`` but be sure to recover the original
+before you submit your work.
+
+If this works, you are able to use the network; your next build would
+be the bootloader, which is the first real application that goes beyond
+developer toys.
+
+
+Build 5: Bootloader
+-------------------
+
+This is the first firmware function that actually reflects a useful
+application.  The bootloader sets up an IP4 local address using IP4LL,
+and at that address runs a TFTP server that reveals the contents of
+flash memory.  While the bootloader is active, it will support LAN
+access to the flash memory, even for writing.  Your best bet would be
+to first download the entire contents of flash, of course.
+
+Note that the bootloader will only run as long as the phone is off-hook;
+if it is on-hook during boot, it will skip to the actual application.
+Given that development machines are usually open, the horn is usually
+not on the hook; whereas in an office situation, a reboot would usually
+be performed with the phone on-hook and so the bootloader would be
+skipped.  This also rules out various abuse patterns.
+
+
+Build 6: SIP phone / doorbell / alarm clock
+-------------------------------------------
+
+You can now select the firmware functions that you are really after.
+
index efd2180..37c898a 100644 (file)
@@ -1,3 +1,8 @@
+TODO: top_main() can return to invoke "next boot option" cyclically
+TODO: bool bottom_phone_is_offhook (void);
+TODO: TIME_MSEC, TIME_SEC, TIME_MIN, TIME_HOUR, TIME_DAY
+TODO: TIME_BEFORE(a,b)
+
 ----------------------------------------------
 Kernel API between Phone Bottom and Top Halves
 ----------------------------------------------
index fd596bd..fc85a7e 100644 (file)
 
 #define LED_IDX_LINEKEYS 0
 
-#if HAS_LED_LINEKEYS
+#if HAVE_LED_LINEKEYS
 #   define LED_IDX_GENERIC (LED_IDX_LINEKEYS+NUM_LINEKEYS)
 #else
 #   define LED_IDX_GENERIC LED_IDX_LINEKEYS
 #endif
 
-#if HAS_LED_GENERIC
-#   define LED_IDX_MESSAGE (LED_IDX_GENERIC+HAS_KBD_GENERIC)
+#if HAVE_LED_GENERIC
+#   define LED_IDX_MESSAGE (LED_IDX_GENERIC+HAVE_KBD_GENERIC)
 #else
 #   define LED_IDX_MESSAGE LED_IDX_GENERIC
 #endif
 
-#if HAS_LED_MESSAGE
-#   define LED_IDX_MUTE (LED_IDX_GENERIC+1)
+#if HAVE_LED_MESSAGE
+#   define LED_IDX_MUTE (LED_IDX_MESSAGE+1)
 #else
-#   define LED_IDX_MUTE LED_IDX_GENERIC
+#   define LED_IDX_MUTE LED_IDX_MESSAGE
 #endif
 
-#if HAS_LED_MUTE
+#if HAVE_LED_MUTE
 #   define LED_IDX_HANDSET (LED_IDX_MUTE+1)
 #else
 #   define LED_IDX_HANDSET LED_IDX_MUTE
 #endif
 
-#if HAS_LED_HANDSET
+#if HAVE_LED_HANDSET
 #   define LED_IDX_HEADSET (LED_IDX_HANDSET+1)
 #else
 #   define LED_IDX_HEADSET LED_IDX_HANDSET
 #endif
 
-#if HAS_LED_HEADSET
+#if HAVE_LED_HEADSET
 #   define LED_IDX_SPEAKERPHONE (LED_IDX_HEADSET+1)
 #else
 #   define LED_IDX_SPEAKERPHONE LED_IDX_HEADSET
 #endif
 
-#if HAS_LED_SPEAKERPHONE
+#if HAVE_LED_SPEAKERPHONE
 #   define LED_IDX_BACKLIGHT (LED_IDX_SPEAKERPHONE+1)
 #else
 #   define LED_IDX_BACKLIGHT LED_IDX_SPEAKERPHONE
 #endif
 
-#if HAS_LED_BACKLIGHT
+#if HAVE_LED_BACKLIGHT
 #   define LED_IDX_COUNT (LED_IDX_BACKLIGHT+1)
 #else
 #   define LED_IDX_COUNT LED_IDX_BACKLIGHT
@@ -107,10 +107,10 @@ typedef uint8_t led_colour_t;
  * NONE for no flashing at all.
  */
 typedef timing_t led_flashtime_t;
-#define LED_FLASHTIME_NONE     ((led_flashtime_t) (   0 * TIME_MSEC))
-#define LED_FLASHTIME_FAST     ((led_flashtime_t) ( 500 * TIME_MSEC))
-#define LED_FLASHTIME_MEDIUM   ((led_flashtime_t) (1000 * TIME_MSEC))
-#define LED_FLASHTIME_SLOW     ((led_flashtime_t) (2000 * TIME_MSEC))
+#define LED_FLASHTIME_NONE     ((led_flashtime_t) (TIME_MSEC(0)   ))
+#define LED_FLASHTIME_FAST     ((led_flashtime_t) (TIME_MSEC(500) ))
+#define LED_FLASHTIME_MEDIUM   ((led_flashtime_t) (TIME_MSEC(1000)))
+#define LED_FLASHTIME_SLOW     ((led_flashtime_t) (TIME_MSEC(2000)))
 
 
 /* Top-half operations to manipulate LED states */
index 9705ac7..a993265 100644 (file)
@@ -56,7 +56,7 @@
  * }
  */
 
-#define BPF_BEGIN(fname) uint32_t fname (uint8_t *P, uint32_t L, uint32_t *M) { register uint32_t A, X=htonl ((uint32_t) P), S; register int k;
+#define BPF_BEGIN(fname) intptr_t fname (uint8_t *P, uint32_t L, uint32_t *M) { register uint32_t A, X=htonl ((uint32_t) P), S; register int k;
 #define BPF_LABEL(l) l:
 #define BPF_END() }
 #define BPF_TAIL(fname) return (fname) (P, L, M);
index 0d9652a..e7aed8d 100644 (file)
@@ -36,8 +36,10 @@ enum mem_netinput {
        MEM_IP4_DST,
        MEM_ETHER_SRC,
        MEM_ETHER_DST,
-       MEM_UDP4_PORTS,
-       MEM_UDP6_PORTS,
+       MEM_UDP4_SRC_PORT,
+       MEM_UDP4_DST_PORT,
+       MEM_UDP6_SRC_PORT,
+       MEM_UDP6_DST_PORT,
        MEM_VLAN_ID,
        MEM_BINDING6,
        MEM_IP6_DST,
@@ -65,6 +67,7 @@ void netcore_bootstrap_initiate (void);
 void netcore_bootstrap_shutdown (void);
 
 uint8_t *net_arp_reply (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
+uint8_t *net_arp_query (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
 uint8_t *net_dhcp4 (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
 uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
 uint8_t *net_rtcp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
index 673ce87..b0a5ff6 100644 (file)
@@ -13,8 +13,9 @@
 
 /* The bottom defines a few useful things:
  *   typedef uint..._t timing_t;
- *   #define TIME_MSEC ...
- *   #define TIME_SEC  ...
+ *   #define TIME_MSEC(x) ...
+ *   #define TIME_SEC(x) ...
+ *   #define TIME_BEOFRE(x,y) ...
  * The former can be used as a parameter without pointers;
  * the TIME_xxx define such periods in terms of that time.
  */
diff --git a/include/bottom/grandstream.h b/include/bottom/grandstream.h
new file mode 100644 (file)
index 0000000..d1c8161
--- /dev/null
@@ -0,0 +1,14 @@
+/* Grandstream-specific definitions, split up per model where needed */
+
+#ifndef HEADER_GRANDSTREAM
+#define HEADER_GRANDSTREAM
+
+/* Settings for Budgetone devices */
+#if defined CONFIG_TARGET_GRANDSTREAM_BT20x || defined CONFIG_TARGET_GRANDSTREAM_BT10x
+#define HAVE_LED_MESSAGE 1
+#define HAVE_LED_BACKLIGHT 1
+#endif
+
+
+#endif
+
diff --git a/include/bottom/linuxtuntest.h b/include/bottom/linuxtuntest.h
new file mode 100644 (file)
index 0000000..d9b6065
--- /dev/null
@@ -0,0 +1,12 @@
+
+#include <stdint.h>
+
+typedef uint64_t timing_t;
+
+#define TIMER_NULL 0
+
+#define TIME_MSEC(x)   ((x))
+#define TIME_SEC(x)    ((x)*1000)
+#define TIME_MIN(x)    ((x)*1000*60)
+#define TIME_HOUR(x)   ((x)*1000*60*60)
+#define TIME_DAY(x)    ((x)*1000*60*60*24)
diff --git a/include/bottom/tic55x.h b/include/bottom/tic55x.h
new file mode 100644 (file)
index 0000000..2dbb8f8
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * tic55x bottom support definitions
+ *
+ * Below:
+ *  - definitions for this architecture to service the top half
+ *  - definitions to bind bottom half files together
+ *
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+/* The timer is the top 32-bit half of timer0 */
+typedef uint32_t timing_t;
+#define TIME_BEFORE(x,y)       (((x)-(y)) >> 31)
+
+#define TIMER_NULL 0
+
+#define TIME_MSEC(x)   ((x))
+#define TIME_SEC(x)    ((x)*1000)
+#define TIME_MIN(x)    ((x)*1000*60)
+#define TIME_HOUR(x)   ((x)*1000*60*60)
+#define TIME_DAY(x)    ((x)*1000*60*60*24)
+
+
+/* Critical region definitions */
+#define bottom_critical_region_begin() _disable_interrupts()
+#define bottom_critical_region_end()    _enable_interrupts()
+
+
+/* Following definitions are only available if BOTTOM is defined */
+
+
+#ifdef BOTTOM
+
+/* Interrupt Enable Registers (memory-mapped) */
+extern volatile uint16_t IER0, IER1;
+asm ("_IER0 .set 0x0000");
+asm ("_IER1 .set 0x0045");
+extern volatile uint16_t IFR0, IFR1;
+asm ("_IFR0 .set 0x0001");
+asm ("_IFR1 .set 0x0046");
+
+#define REGBIT_IER0_TINT0      4
+#define REGBIT_IER1_TINT1      6
+
+extern volatile uint16_t IVPD, IVPH;
+asm ("_IVPD .set 0x0049");
+asm ("_IVPH .set 0x004a");
+
+void setup_interrupts (void);
+
+/* General Purpose I/O registers */
+extern volatile uint16_t ioport IODIR, IODATA;
+asm ("_IODIR .set 0x3400");
+asm ("_IODATA .set 0x3401");
+
+/* Pin Control Registers for McBSP0, McBSP1 */
+extern volatile uint16_t ioport PCR0, PCR1;
+asm ("_PCR0 .set 0x2812");
+asm ("_PCR1 .set 0x2c12");
+
+#define REGBIT_PCR_DXSTAT      5
+#define REGBIT_PCR_RIOEN       12
+#define REGBIT_PCR_XIOEN       13
+
+/* Timer0/1 configuration registers */
+extern volatile uint16_t ioport GPTCLK_0;
+extern volatile uint16_t ioport GPTCNT1_0, GPTCNT2_0, GPTCNT3_0, GPTCNT4_0;
+extern volatile uint16_t ioport GPTPRD1_0, GPTPRD2_0, GPTPRD3_0, GPTPRD4_0;
+extern volatile uint16_t ioport GPTCTL1_0, GPTCTL2_0, GPTGCTL1_0;
+asm ("_GPTCLK_0 .set 0x1003");
+asm ("_GPTCNT1_0 .set 0x1008");
+asm ("_GPTCNT2_0 .set 0x1009");
+asm ("_GPTCNT3_0 .set 0x100a");
+asm ("_GPTCNT4_0 .set 0x100b");
+asm ("_GPTPRD1_0 .set 0x100c");
+asm ("_GPTPRD2_0 .set 0x100d");
+asm ("_GPTPRD3_0 .set 0x100e");
+asm ("_GPTPRD4_0 .set 0x100f");
+asm ("_GPTCTL1_0 .set 0x1010");
+asm ("_GPTCTL2_0 .set 0x1011");
+asm ("_GPTGCTL1_0 .set 0x1012");
+
+extern volatile uint16_t ioport GPTCLK_1;
+extern volatile uint16_t ioport GPTCNT1_1, GPTCNT2_1, GPTCNT3_1, GPTCNT4_1;
+extern volatile uint16_t ioport GPTPRD1_1, GPTPRD2_1, GPTPRD3_1, GPTPRD4_1;
+extern volatile uint16_t ioport GPTCTL1_1, GPTCTL2_1, GPTGCTL1_1;
+asm ("_GPTCLK_1 .set 0x2403");
+asm ("_GPTCNT1_1 .set 0x2408");
+asm ("_GPTCNT2_1 .set 0x2409");
+asm ("_GPTCNT3_1 .set 0x240a");
+asm ("_GPTCNT4_1 .set 0x240b");
+asm ("_GPTPRD1_1 .set 0x240c");
+asm ("_GPTPRD2_1 .set 0x240d");
+asm ("_GPTPRD3_1 .set 0x240e");
+asm ("_GPTPRD4_1 .set 0x240f");
+asm ("_GPTCTL1_1 .set 0x2410");
+asm ("_GPTCTL2_1 .set 0x2411");
+asm ("_GPTGCTL1_1 .set 0x2412");
+
+#define REGVAL_GCTL_TIMMODE_DUAL32CHAINED 0x0c
+#define REGVAL_GCTL_TIM12RS 0x01
+#define REGVAL_GCTL_TIM34RS 0x02
+
+#define REGVAL_CTL12_ENAMODE_MASK      0xc0
+#define REGVAL_CTL12_ENAMODE_ONETIME   0x40
+#define REGVAL_CTL12_ENAMODE_CONTINUOUS        0x80
+#define REGVAL_CTL12_CP                        0x08
+#define REGVAL_CTL12_TSTAT             0x01
+
+
+/* Idle mode configuration parameters */
+extern volatile uint16_t ioport ICR, PICR;
+asm ("_ICR .set 0x0001");
+asm ("_PICR .set 0x9400");
+
+#define REGBIT_ICR_CLKEI 9
+#define REGBIT_ICR_IPORTI 8
+#define REGBIT_ICR_MPORTI 7
+#define REGBIT_ICR_XPORTI 6
+#define REGBIT_ICR_EMIFI 5
+#define REGBIT_ICR_CLKI 4
+#define REGBIT_ICR_PERI 3
+#define REGBIT_ICR_ICACHEI 2
+#define REGBIT_ICR_MPI 1
+#define REGBIT_ICR_CPUI 0
+
+#define REGBIT_PICR_MISC 13
+#define REGBIT_PICR_EMIF 12
+#define REGBIT_PICR_BIOST 11
+#define REGBIT_PICR_WDT 10
+#define REGBIT_PICR_PIO 9
+#define REGBIT_PICR_URT 8
+#define REGBIT_PICR_I2C 7
+#define REGBIT_PICR_ID 6
+#define REGBIT_PICR_IO 6
+#define REGBIT_PICR_SP1 3
+#define REGBIT_PICR_SP0 2
+#define REGBIT_PICR_TIM1 1
+#define REGBIT_PICR_TIM0 0
+
+
+#endif
diff --git a/include/stdbool.h b/include/stdbool.h
new file mode 100644 (file)
index 0000000..c2d7886
--- /dev/null
@@ -0,0 +1,6 @@
+/* Backup for unsupportive compiles */
+
+typedef enum {
+       false = 0,
+       true  = 1
+} bool;
diff --git a/src/README b/src/README
new file mode 100644 (file)
index 0000000..369214c
--- /dev/null
@@ -0,0 +1,14 @@
+==============================================
+README for source directory of 0cpm firmerware
+==============================================
+
+kernel Mainly holds the entrance routines top_xxx
+
+net    Protocols, checksums, packet construction/interpretation
+
+phone  Telephony logic, user experience
+
+target Platform definitions, platform being make + model
+
+driver Drivers for specific chips in the design
+
index 139597f..1eafb9d 100644 (file)
@@ -1,2 +1,9 @@
 
+objs-bottom-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += src/driver/tic55x/grandstream-bt20x.o
+
+#TODO: replace rts55.lib with bootstrapping in src/driver/tic55x/trampoline.o
+
+objs-bottom-$(CONFIG_PLATFORM_TIC55x) += src/driver/tic55x/int.o src/driver/tic55x/timer.o src/driver/tic55x/isrmap.o #NOPE# src/driver/tic55x/gpio.o #TODO# 
+
+metavars-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += SYSCLK1_TO_MS_DIVIDER=4096
 
diff --git a/src/driver/tic55x/gpio.c b/src/driver/tic55x/gpio.c
new file mode 100644 (file)
index 0000000..aa469d9
--- /dev/null
@@ -0,0 +1,28 @@
+/* GPIO driver for tic55x */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define BOTTOM
+#include <config.h>
+
+void tic55x_output_set (uint16_t regaddr, uint16_t regval) {
+       * ( (ioport uint16_t *) regaddr) = regval;
+}
+
+uint16_t tic55x_input_get (uint16_t regaddr) {
+       return * ( (uint16_t *) regaddr);
+}
+
+void tic55x_output_set_bit (uint16_t regaddr, uint8_t regbit, bool value) {
+       if (value) {
+               * ( (ioport uint16_t *) regaddr) |=    1 << regbit ;
+       } else {
+               * ( (ioport uint16_t *) regaddr) &= ~( 1 << regbit);
+       }
+}
+
+bool tic55x_input_get_bit (uint16_t regaddr, uint8_t regbit) {
+       uint16_t value = * (ioport uint16_t *) regaddr;
+       return (value & (1 << regbit)) ? true: false;
+}
diff --git a/src/driver/tic55x/grandstream-bt20x.c b/src/driver/tic55x/grandstream-bt20x.c
new file mode 100644 (file)
index 0000000..c68bddc
--- /dev/null
@@ -0,0 +1,61 @@
+/* Grandstream BT20x driver as an extension to the tic55x driver */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define BOTTOM
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+
+/* Bottom-half operations to manipulate LED states */
+void bottom_led_set (led_idx_t ledidx, led_colour_t col) {
+       switch (ledidx) {
+       case LED_IDX_MESSAGE:
+               //TODO: Figure out which pin -- incorrectly change backlight
+       case LED_IDX_BACKLIGHT:
+               // Set bit DXSTAT=5 in PCR=0x2812 to 1/0
+               if (col != 0) {
+                       PCR0 |=     1 << REGBIT_PCR_DXSTAT  ;
+               } else {
+                       PCR0 &= ~ ( 1 << REGBIT_PCR_DXSTAT );
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+
+/* See if the phone (actually, the horn) is offhook */
+bool bottom_phone_is_offhook (void) {
+       // The hook switch is attached to GPIO pin 5
+       // return ! tic55x_input_get_bit (REGADDR_IODATA, 5);
+       return (IODATA & (1 << 5)) != 0;
+}
+
+
+/* Setup the connectivity of the TIC55x as used on Grandstream BT20x */
+void main (void) {
+       led_colour_t led = LED_STABLE_ON;
+       bottom_critical_region_begin (); // _disable_interrupts ();
+       IER0 = IER1 = 0x0000;
+       tic55x_setup_timers ();
+       tic55x_setup_interrupts ();
+       //TODO// IER0 = 0xdefc;
+       //TODO// IER1 = 0x00ff;
+       IER0 = (1 << REGBIT_IER0_TINT0);
+       PCR0 = (1 << REGBIT_PCR_XIOEN) | (1 << REGBIT_PCR_RIOEN);
+       while (true) {
+               uint32_t ctr;
+               bottom_led_set (LED_IDX_MESSAGE, led);
+               for (ctr=6500000; ctr>0; ctr--) { ; }
+               led ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+       }
+       top_main ();
+}
+
diff --git a/src/driver/tic55x/int.c b/src/driver/tic55x/int.c
new file mode 100644 (file)
index 0000000..f837327
--- /dev/null
@@ -0,0 +1,64 @@
+/* tic55x interrupt handling */
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define BOTTOM
+#include <config.h>
+
+#include <0cpm/cpu.h>
+
+
+/* This flag is set by every interrupt that calls a top_XXX function.
+ * It indicates that the top *may* have new work to do.  This is used
+ * to establish whether the bottom can go to sleep, as part of a
+ * two-phase sleep protocol: bottom_sleep_prepare() clears this flag,
+ * then the top checks if any work is pending at that time, and then
+ * bottom_sleep_commit() is called.  The latter will fall through
+ * immediately if the flag has been set meanwhile, as the top may
+ * have missed incoming work.
+ */
+bool tic55x_top_has_been_interrupted;
+
+
+#if 0
+void bottom_sleep_prepare (void) {
+       tic55x_top_has_been_interrupted = false;
+}
+
+void bottom_sleep_commit (sleep_depth_t depth) {
+       bottom_critical_region_begin ();
+       if (!tic55x_top_has_been_interrupted) {
+               if (depth == SLEEP_HIBERNATE) {
+                       // Hibernate: Idle CPU and most I/O
+                       ICR = (1 << REGBIT_ICR_CPUI) | (1 << REGBIT_ICR_ICACHEI) | (1 << REGBIT_ICR_MPI) | (1 << REGBIT_ICR_PERI);
+                       PICR = (1 << REGBIT_PICR_MISC) | (1 << REGBIT_PICR_BIOST) | (1 << REGBIT_PICR_WDT) | (1 << REGBIT_PICR_URT) | (1 << REGBIT_PICR_I2C) | (1 << REGBIT_PICR_SP1) | (1 << REGBIT_PICR_SP0);
+               } else {
+                       // Snooze: Idle CPU but nothing more
+                       ICR = 1 << REGBIT_ICR_CPUI;
+               }
+               asm ("  IDLE");
+       }
+       bottom_critical_region_end ();
+}
+#endif
+
+interrupt void tic55x_no_isr (void) {
+#if 0
+       /* No action */ ;
+#endif
+}
+
+
+// TODO -- probably do this in the trampoline code?
+void tic55x_setup_interrupts (void) {
+       // extern uint32_t interrupt_table;
+       // IVPD = (uint16_t) (((uint32_t) interrupt_table) >> 8);
+       asm (
+"      .ref    isrmap0, isrmap1\n"
+"      mov     #(isrmap0 >> 8), mmap(_IVPD)\n"
+"      mov     #(isrmap1 >> 8), mmap(_IVPH)\n"
+);
+}
+
diff --git a/src/driver/tic55x/isrmap.asm b/src/driver/tic55x/isrmap.asm
new file mode 100644 (file)
index 0000000..350a2f5
--- /dev/null
@@ -0,0 +1,86 @@
+               ; Create a subsection with interrupt service routine vectors
+               .sect   ".isrmap"
+
+               .align  256
+               .vli_off
+
+               .def    isrmap0
+               .def    isrmap1
+
+               .ref    _c_int00
+               .ref    _tic55x_no_isr
+               .ref    _tic55x_tint0_isr
+
+_tic55x_bootld .set    0xff8000
+
+isrmap0:
+resetvect      .ivec   _c_int00, NO_RETA
+nmi            .ivec   _tic55x_no_isr
+int0           .ivec   _tic55x_no_isr
+int2           .ivec   _tic55x_no_isr
+tint0          .ivec   _tic55x_tint0_isr
+rint0          .ivec   _tic55x_no_isr
+rint1          .ivec   _tic55x_no_isr
+xint1          .ivec   _tic55x_no_isr
+lckint         .ivec   _tic55x_no_isr
+dmac1          .ivec   _tic55x_no_isr
+dspint         .ivec   _tic55x_no_isr
+int3           .ivec   _tic55x_no_isr
+uart           .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+dmac4          .ivec   _tic55x_no_isr
+dmac5          .ivec   _tic55x_no_isr
+int1           .ivec   _tic55x_no_isr
+xint0          .ivec   _tic55x_no_isr
+dmac0          .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+dmac2          .ivec   _tic55x_no_isr
+dmac3          .ivec   _tic55x_no_isr
+tint1          .ivec   _tic55x_no_isr
+iic            .ivec   _tic55x_no_isr
+berr           .ivec   _tic55x_no_isr
+dlog           .ivec   _tic55x_no_isr
+rtos           .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+
+isrmap1:
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+               .ivec   _tic55x_no_isr
+
+               .sect   ".text"
+               .vli_on
+
diff --git a/src/driver/tic55x/timer.c b/src/driver/tic55x/timer.c
new file mode 100644 (file)
index 0000000..fc9a349
--- /dev/null
@@ -0,0 +1,141 @@
+/* General timer management.
+ *
+ * The tic55x has multiple 64-bit timers, we'll use timer0 and timer1.
+ *
+ * Since a timer can either be set to fire or continue to count,
+ * but not both, we'll need two timers:
+ *
+ *  - timer0 counts until the next time-based interrupt
+ *  - timer1 counts the time since the system started
+ *
+ * The reason for assigning the timers like this?  timer0 has a higher
+ * interrupt level than, say, uart.  That helps to get more accuracy
+ * from a realtime system.
+ *
+ * The tic55x timers are 64-bit, and can be split in two halves.
+ *
+ * The first half (CNT4:CNT3 and PRD4:PRD3) is used as a prescale-counter,
+ * to reduce the crystal clock frequency to a 1 ms pace.  This is chained
+ * to the second half (CNT2:CNT1), which then forms the actual timer used
+ * by the 0cpm firmerware.
+ *
+ * The actual 2:1 timer1 is a 32-bit counter that counts round and round
+ * in circles, without ever causing an interrupt.  The actual 2:1 timer0
+ * is set to the next interrupt time, and causes an interrupt when it is
+ * reached.  This setting is based on the requested interrupt time and
+ * the value in timer1 at the time of the request.
+ *
+ * The top half takes care of setting up timer queues to implement a more
+ * general timing discipline, processing interrupts at such timeouts.
+ *
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define BOTTOM
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/irq.h>
+#include <0cpm/timer.h>
+
+
+/* Global variables */
+
+static timing_t current_timer = 0;
+
+
+/* Read the current time from timer1's top part.  Be careful about
+ * timer increments between the two word reads.
+ *
+ * The tic55x copies timer registers to shadow registers to ensure
+ * that all values are in sync; the code need not verify that.
+ */
+timing_t bottom_time (void) {
+       uint16_t cnt1 = GPTCNT1_1;
+       uint16_t cnt2 = GPTCNT2_1;
+       return (((timing_t) cnt2) << 16) | ((timing_t) cnt1);
+}
+
+
+/* Setup a new timing for the following timer interrupt.  If one is
+ * currently underway, disable it so it will not spark new interrupts
+ * after this function returns.
+ */
+timing_t bottom_timer_set (timing_t tim) {
+       timing_t intval, previous;
+       /* First of all, reset timer0 so it can be configured */
+       GPTGCTL1_0 &= ~ ( REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS );
+       IFR0 = (1 << REGBIT_IER0_TINT0);
+       previous = current_timer;
+       current_timer = tim;
+       /* Poll the running timer1 */
+       // tim = bottom_time () + TIME_MSEC(1500);
+       intval = tim - bottom_time ();
+// intval = intval & 0x0000ffff;
+       if ((intval == 0) || (intval >> 31)) {
+               /* Cause interrupt right now, do not run the timer */
+               top_timer_expiration (tim);
+               current_timer = 0;
+bottom_led_set (0, 1);
+{ uint32_t ctr = 6500000; while (ctr > 0) ctr--; }
+bottom_led_set (0, 0);
+{ uint32_t ctr = 6500000; while (ctr > 0) ctr--; }
+               return previous;
+       }
+       /* Setup counter value and period */
+       GPTCNT3_0 = GPTCNT3_1;  /* also copies GPTCNT4_1 to shadow register */
+       GPTCNT4_0 = GPTCNT4_1;  /* retrieve shadow register for GPTCNT4_1 */
+       GPTCNT2_0 =
+       GPTCNT1_0 = 0x0000;
+       GPTPRD2_0 = (uint16_t) (intval >> 16   );
+       GPTPRD1_0 = (uint16_t)  intval          ; //(intval & 0xffff);
+       /* Finally, enable timer1 so it can cause interrupts */
+       GPTGCTL1_0 |= REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS;
+bottom_led_set (0, 1);
+{ uint32_t ctr = 650000; while (ctr > 0) ctr--; }
+bottom_led_set (0, 0);
+{ uint32_t ctr = 650000; while (ctr > 0) ctr--; }
+       return previous;
+}
+
+
+/* Timer interrupt handler for timer0 expiration */
+interrupt void tic55x_tint0_isr (void) {
+#if 0
+       extern bool tic55x_top_has_been_interrupted;
+       timing_t now = bottom_time ();
+       current_timer = 0;
+       top_timer_expiration (now);
+       tic55x_top_has_been_interrupted = true;
+#endif
+}
+
+
+/* Setup timers and the corresponding interrupts for timer0/timer1
+ */
+void tic55x_setup_timers (void) {
+       /* Be sure that the timers are reset, so they can be configured */
+       GPTGCTL1_0 =
+       GPTGCTL1_1 = 0;
+       /* Let the lower half of timer0/timer1 count once per ms */
+       GPTPRD4_0 =
+       GPTPRD4_1 = (uint16_t) ((SYSCLK1_TO_MS_DIVIDER-1) >> 16);
+       GPTPRD3_0 =
+       GPTPRD3_1 = (uint16_t) ((SYSCLK1_TO_MS_DIVIDER-1) & 0xffff);
+       /* Let the upper half of timer1 count with a 2^32 period */
+       GPTPRD2_1 =
+       GPTPRD1_1 = 0xffff;
+       /* Let timer1 run entirely free; let timer0 lower half run free */
+       GPTCTL1_0 = REGVAL_CTL12_ENAMODE_ONETIME;
+       GPTCTL1_1 = REGVAL_CTL12_ENAMODE_CONTINUOUS;
+       GPTGCTL1_0 = REGVAL_GCTL_TIMMODE_DUAL32CHAINED;
+       GPTGCTL1_1 = REGVAL_GCTL_TIMMODE_DUAL32CHAINED | REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS;
+       /* Clear, then permit interrupts from timer0 */
+       IFR0  = (1 << REGBIT_IER0_TINT0);
+}
+
diff --git a/src/driver/util/ledsimu.c b/src/driver/util/ledsimu.c
new file mode 100644 (file)
index 0000000..dd8778d
--- /dev/null
@@ -0,0 +1,109 @@
+/* LED simulation support -- print them in tabbed columns
+ *
+ * Descriptions below are all restricted to 7 chars or less, so they
+ * can be printed with a '\t' in between.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdlib.h>
+
+#include <config.h>
+
+#include <0cpm/led.h>
+
+
+char *led_colours_2 [] = { "off", "green" };
+char *led_colours_3 [] = { "off", "green", "red" };
+
+struct led_descript {
+       char *name;
+       char **states;
+       char *current;
+};
+
+/*
+ * LED descriptive structure, following the structure of led.h
+ */
+struct led_descript num2descr [] = {
+#if HAVE_LED_LINEKEYS
+#  if NUM_LINEKEYS >= 1
+       { "line1", led_colours_3, NULL, },
+#  endif
+#  if NUM_LINEKEYS >= 2
+       { "line2", led_colours_3, NULL, },
+#  endif
+#  if NUM_LINEKEYS >= 3
+       { "line3", led_colours_3, NULL, },
+#  endif
+#  if NUM_LINEKEYS >= 4
+       { "line4", led_colours_3, NULL, },
+#  endif
+#  if NUM_LINEKEYS >= 5
+       { "line5", led_colours_3, NULL, },
+#  endif
+#  if NUM_LINEKEYS >= 6
+       { "line6", led_colours_3, NULL, },
+#  endif
+#  if NUM_LINEKEYS >= 7
+#      error "Please define additional line LEDs in ledsimu.c"
+#  endif
+#endif
+#if HAVE_LED_GENERIC
+#      error "Please define generic LEDs in ledsimu.c"
+#endif
+#if HAVE_LED_MESSAGE
+       { "vmail", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_MUTE
+       { "mute", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_HANDSET
+       { "handset", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_HEADSET
+       { "headset", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_SPEAKERPHONE
+       { "speaker", led_colours_2, NULL, },
+#endif
+#if HAVE_LED_BACKLIGHT
+       { "display", led_colours_2, NULL, },
+#endif
+};
+
+
+void bottom_led_set (led_idx_t lednum, led_colour_t col) {
+       int i;
+       struct timeval tv;
+       gettimeofday (&tv, NULL);
+       static headctr = 0;
+       if (headctr++ % 20 == 0) {
+               for (i = 0; i < LED_IDX_COUNT; i++) {
+                       printf ("\t%s", num2descr [i].name);
+               }
+               printf ("\n");
+       }
+       printf ("%3d.%03d", tv.tv_sec, tv.tv_usec / 1000);
+       char capscol [8];
+       char *colnm = num2descr [lednum].states [col];
+       for (i = 0; i < 7; i++) {
+               if (colnm [i] == 0) {
+                       break;
+               }
+               capscol [i] = toupper (colnm [i]);
+       }
+       capscol [i] = '\0';
+       for (i = 0; i < LED_IDX_COUNT; i++) {
+               if (i == lednum) {
+                       colnm = capscol;
+               } else if (num2descr [lednum].current != NULL) {
+                       colnm = num2descr [lednum].current;
+               } else {
+                       colnm = "UNSET";
+               }
+               printf ("\t%s", colnm);
+       }
+       printf ("\n");
+}
index d8d0ced..9a18e7f 100644 (file)
@@ -58,6 +58,11 @@ uint8_t *net_arp_reply (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
        return NULL;
 }
 
+uint8_t *net_arp_query (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
+       printf ("Received: ARP Query\n");
+       return NULL;
+}
+
 uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
        printf ("Received: RTP\n");
        return NULL;
@@ -114,12 +119,6 @@ void init (void) {
  * Environment simulation functions
  */
 
-void bottom_led_set (led_idx_t ledidx, led_colour_t col) {
-       char *colmap [] = { "off", "green", "red" };
-       printf ("LED #%d switches to colour #%d (%s)\n",
-                       ledidx, col, (col < 3)? colmap [col]: "out-of-range");
-}
-
 timing_t bottom_time (void) {
        struct timeval now;
        timing_t retval;
diff --git a/src/function/Kconfig b/src/function/Kconfig
new file mode 100644 (file)
index 0000000..ca7d130
--- /dev/null
@@ -0,0 +1,128 @@
+# Function for the target image
+
+menu "Firmerware functions"
+
+choice
+       prompt "Functionality to build"
+       default MAINFUNCTION_SIP_PHONE
+
+source "src/function/Kconfig.devel"
+
+config MAINFUNCTION_SIP_PHONE
+       bool "SIP phone over IPv6"
+       help
+         This is the main target for the 0cpm firmerware.  It implements
+         SIP phone functionality over IPv6.  Included are facilities to
+         obtain IPv6 connectivity on all networks.
+
+
+config MAINFUNCTION_SIP_DOORBELL
+       bool "SIP doorbell"
+       help
+         This is an alternative main target for the 0cpm firmerware.
+         It implements a doorbell that is switched off until a button
+         is pressed.  As soon as the device boots, it will dial out to
+         a predefined number on a predefined server.
+
+         This is not quite the same as a phone configured as a hotline.
+         Such a phone would always be switched on, even though normal
+         use would not include calling to the device.  So, to save
+         energy, the doorbell application assumes that a phone is
+         switched off when not in use.  The device will keep itself
+         switched on until it is done with its task.
+
+
+config MAINFUNCTION_SIP_ALARMCLOCK
+       bool "SIP alarm clock"
+       help
+         This is an alternate main target for the 0cpm firmerware.
+         It implements an alarm clock that does not ring the phone,
+         but rather picks up immediately and plays whatever sound
+         is sent to it.  It is imagined that a network service would
+         wake up all those souls who have a hard time hearing a
+         rooster nearby.
+
+         To furhter implement the logic of an alarm clock, use of the
+         hook contact will make it speak out the current time.  There
+         is a facility for a button that will set the alarm to go a
+         predefined number of hours after it was pressed.  You might
+         go as far as to wire that to your bed!
+
+
+config MAINFUNCTION_BOOTLOADER
+       bool "Bootloader"
+       help
+         Some phones have less RAM than Flash on board.  On such phones,
+         stability improves with the installation of a small bootloader
+         that is smaller than RAM.  More in general, it helps to upgrade
+         the firmerware under tight local control.
+
+         The bootloader is initiated after a power cycle if (and as long as)
+         the horn is off-hook.  This is not usually the case, so normally
+         the bootloader is skipped quickly.
+
+         While the bootloader is active, all nonvolatile partitions are
+         made available over TFTP for reading and writing.  To aid in
+         automation, the bootloader will push the availability of this
+         TFTP service out over DNS-SD and mDNS, although it will not
+         continue to function as a general DNS-SD server.
+
+         The bootloader does not run over IPv6 and is only routed locally;
+         to that end, it acquires an IP4LL "zeroconfig" IP address.  These
+         addresses are not intended to be routed, and are not welcome on
+         the general Internet infrastructure.  This means that bootloader
+         image functions are protected from remote attacks.
+
+endchoice
+
+config FUNCTION_DEVEL_NETCONSOLE
+       bool "LAN-based console"
+       default y if DEVEL=y 
+       default n if DEVEL=n
+       help
+         Direct console traffic for the main application to the network.
+
+         The protocol used for this network console is Logical Link Control.
+         This is an ethernet-level protocol, so it will only work locally.
+
+         This console can also be selected as a main function for the
+         image being built, to test network connectivity.
+
+         TODO: ports
+
+         This facility is normally only of use during development.
+
+config FUNCTION_FIRMWARE_UPGRADES
+       bool "Support firmware upgrades"
+       depends on MAINFUNCTION_SIP_PHONE
+       default n
+       help
+         It is possible, though not strictly required, to support
+         the download and installation of new firmware.  As normal
+         IP addresses are used, this is not as safe as the upgrades
+         that are included in the dedicated bootloader main function.
+
+         If the upgrade fails, the phone will need to be upgraded
+         through the bootloader, if it has one.
+
+         Do not select this option without considering its implications.
+
+config FUNCTION_FIRMWARE_UPGRADES_BOOTLOADER
+       bool "Support bootloader upgrades (DANGEROUS)"
+       depends on FUNCTION_FIRMWARE_UPGRADES
+       default n
+       help
+         This is a dangerous facility!
+
+         Complete remote control over a phone is only possible if all
+         firmware, including even its bootloader, can be upgraded from
+         a remote site.  This option enables that facility.
+
+         Note that this facility makes the phone rather vulnerable.
+         Anyone with access to the phone's TFTP service will be able
+         to upload new firmware to replace it.  You do want to have a
+         tightly controlled firewall to avoid this from being abused.
+
+         TODO: a polling TFTP client may in fact be better?
+
+endmenu
diff --git a/src/function/Kconfig.devel b/src/function/Kconfig.devel
new file mode 100644 (file)
index 0000000..21ebc72
--- /dev/null
@@ -0,0 +1,39 @@
+# Development functions
+
+config MAINFUNCTION_DEVEL_GPIO
+       bool "Test switch / light"
+       depends on DEVEL
+       help
+         This is the simplest possible test program, which can be useful
+         to ensure control over a device during reverse engineering.
+
+         The application continuously scans the hook.  It makes the message
+         LED burn while the phone is off-hook.
+
+config MAINFUNCTION_DEVEL_TIMER
+       bool "Test timer interrupts"
+       depends on DEVEL
+       help
+         This is a very simple test program.  It makes the message LED
+         flash with a 1 second period and a 50% duty cycle.  It can be
+         used to develop timer drivers.
+
+config MAINFUNCTION_DEVEL_KEYBOARD
+       bool "Test keyboard / display"
+       depends on DEVEL
+       help
+         This test processes input from the keyboard, and shows it on
+         the display, as well as printing it to the platform's console,
+         if any.
+
+config MAINFUNCTION_DEVEL_NETWORK
+       bool "Test network"
+       depends on DEVEL
+       select FUNCTION_DEVEL_NETCONSOLE
+       help
+         Run a networked console.  In addition to the usual console
+         functions, respond to any text sent by mapping it to uppercase.
+
+         The details of the networked console are described under the
+         add-on function for this console, one menu level up.
+
diff --git a/src/function/Makefile b/src/function/Makefile
new file mode 100644 (file)
index 0000000..f242217
--- /dev/null
@@ -0,0 +1,20 @@
+# Function-dependent construction of top-objs list
+
+#
+# Actual targets and their constituent object files
+#
+objs-top-$(CONFIG_MAINFUNCTION_SIP_PHONE) += src/function/sip6phone.o bin/top-kernel.o bin/top-net.o bin/top-phone.o
+
+objs-top-$(CONFIG_MAINFUNCTION_BOOTLOADER) += src/function/bootload.o bin/top-kernel.o bin/top-simplenet.o function
+
+#
+# Test targets, useful during reverse engineering and forward development
+#
+objs-top-$(CONFIG_MAINFUNCTION_DEVEL_GPIO) += src/function/develtest/switch2led.o
+
+objs-top-$(CONFIG_MAINFUNCTION_DEVEL_TIMER) += src/function/develtest/timer2led.o
+
+objs-top-$(CONFIG_MAINFUNCTION_DEVEL_KEYBOARD) += src/function/develtest/keys2display.o
+
+objs-top-$(CONFIG_MAINFUNCTION_DEVEL_NETCONSOLE) += src/function/develtest/netconsole.o
+
diff --git a/src/function/bootloader/main.c b/src/function/bootloader/main.c
new file mode 100644 (file)
index 0000000..c88cc04
--- /dev/null
@@ -0,0 +1,45 @@
+/* bootloader -- TFTP on top of IP4LL to reveal flash contents */
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/net.h>
+
+
+/* Bootloader IPv4 acquisition -- through IP4LL */
+void bootloader_net_ip4ll (void) {
+       "TODO: code this function";
+}
+
+
+/* Bootloader announcement of TFTP service -- as DNS-SD, over mDNS */
+void bootloader_announce_tftp (void) {
+       "TODO: code this function";
+}
+
+
+/* Bootloader network handling -- dealing with TFTP, ICMP and ARP */
+void bootloader_handle_net (void) {
+       "TODO: code this function";
+}
+
+
+/* Bootloader main program.  This usually starts before the real app.
+ *
+ * This ends as soon as possible, once the phone is placed on-hook.
+ * As a result, a normal phone reboot (with the phone on-hook) will
+ * immediately skip bootloading and advance to the actual payload.
+ * Also, if a phone is rebooted off-hook and behaves "funny", the
+ * user will quickly learn to place the horn back on the hook.
+ * In development situations, the horn is usually off-hook as a
+ * result of the phone being taken apart.  How practical!
+ */
+void top_main (void) {
+       if (bottom_phone_is_offhook ()) {
+               bootloader_net_ip4ll ();
+               bootloader_announce_tftp ();
+               while (bottom_phone_is_offhook ()) {
+                       bootloader_handle_net ();
+               }
+       }
+}
diff --git a/src/function/develtest/keys2display.c b/src/function/develtest/keys2display.c
new file mode 100644 (file)
index 0000000..c151bfa
--- /dev/null
@@ -0,0 +1,18 @@
+/* keys2display.c -- capture keys and show them on the display */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+void top_main (void) {
+       bottom_critical_region_end ();
+       while (true) {
+               TODO: KEYBOARD AND DISPLAY DRIVING CODE
+       }
+}
+
diff --git a/src/function/develtest/netconsole.c b/src/function/develtest/netconsole.c
new file mode 100644 (file)
index 0000000..d838ce8
--- /dev/null
@@ -0,0 +1,18 @@
+/* netconsole.c -- run a console over LLC over ethernet */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+void top_main (void) {
+       bottom_critical_region_end ();
+       while (true) {
+               TODO: CONSOLE DRIVER OVER LLC
+       }
+}
+
diff --git a/src/function/develtest/switch2led.c b/src/function/develtest/switch2led.c
new file mode 100644 (file)
index 0000000..80d9971
--- /dev/null
@@ -0,0 +1,45 @@
+/* switch2led.c -- simple test where hook contact drives message led */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+
+#define complete_top_main top_main
+
+
+void top_timer_expiration (timing_t when) { ; }
+
+
+void simpler_top_main (void) {
+       while (true) {
+               uint16_t ctr;
+               ctr = 65000;
+               while (ctr > 0) {
+                       ctr--;
+               }
+               bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+               ctr = 65000;
+               while (ctr > 0) {
+                       ctr--;
+               }
+               bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+       }
+}
+
+
+void complete_top_main (void) {
+       while (true) {
+               if (bottom_phone_is_offhook ()) {
+                       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+               } else {
+                       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+               }
+       }
+}
+
diff --git a/src/function/develtest/timer2led.c b/src/function/develtest/timer2led.c
new file mode 100644 (file)
index 0000000..4c82dc5
--- /dev/null
@@ -0,0 +1,138 @@
+/* timer2led.c -- simple test where a timer toggles a LED (T=1s, D=50%) */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define BOTTOM
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/timer.h>
+#include <0cpm/led.h>
+
+
+#define complete_top_main top_main
+
+
+void doesitcount_top_main (void) {
+       uint16_t ctr;
+       timing_t lastcaught = bottom_time ();
+       led_colour_t nextstate = LED_STABLE_OFF;
+       while (true) {
+               if (lastcaught != bottom_time ()) {
+                       lastcaught = bottom_time ();
+                       nextstate ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+                       bottom_led_set (LED_IDX_MESSAGE, nextstate);
+                       ctr = 65000;
+                       while (ctr > 0) {
+                               ctr--;
+                       }
+               }
+       }
+}
+
+
+void noirq_top_main (void) {
+       led_colour_t nextstate = LED_STABLE_OFF;
+       timing_t nextirq = bottom_time ();
+       while (true) {
+               if (TIME_BEFORE (nextirq, bottom_time ())) {
+                       nextstate ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+                       bottom_led_set (LED_IDX_MESSAGE, nextstate);
+                       // nextirq = bottom_time () + TIME_MSEC(500);
+                       nextirq += TIME_MSEC(500);
+               }
+       }
+}
+
+
+void irqpolling_top_main (void) {
+       timing_t nextirq;
+redo:
+       nextirq = bottom_time () + TIME_MSEC(1500);
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+{ uint16_t ctr = 65000; while (ctr > 0) ctr--; }
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+{ uint16_t ctr = 65000; while (ctr > 0) ctr--; }
+       bottom_timer_set (nextirq);
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+{ uint16_t ctr = 65000; while (ctr > 0) ctr--; }
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+{ uint16_t ctr = 65000; while (ctr > 0) ctr--; }
+       while (true) {
+#ifdef INCLUDE_BOTTOM_IRQ_ACCESS_HALFWAY_DEVELOPMENT_HACK
+               if ("irq_flag_is_set") {
+                       "clear_irq_flag";
+                       bottom_timer_expiration (bottom_time () + TIME_MSEC(1500));
+               }
+#else
+               if ((GPTCNT1_0==0) && (GPTCNT2_0==0)) {
+                       IFR0 = (1 << REGBIT_IER0_TINT0);
+                       // bottom_timer_expiration (bottom_time () + TIME_MSEC(1500));
+                       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+                       goto done;
+               } else {
+                       uint16_t ctr;
+                       uint16_t ctr1a, ctr1b;
+                       ctr1a = GPTCNT1_0;
+                       ctr1b = GPTCNT2_0;
+                       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+                       ctr = 65000;
+                       while (ctr > 0) {
+                               ctr--;
+                       }
+                       if ((ctr1a != GPTCNT1_0) || (ctr1b != GPTCNT2_0)) {
+                               bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+                               ctr = 65000;
+                               while (ctr > 0) {
+                                       ctr--;
+                               }
+                       }
+               }
+#endif
+       }
+done:
+while (!bottom_phone_is_offhook ()) {
+       ;
+}
+while (bottom_phone_is_offhook ()) {
+       ;
+}
+goto redo;
+}
+
+
+volatile bool busy = false;
+
+void top_timer_expiration (timing_t exptime) {
+       uint16_t ctr;
+       // static led_colour_t nextstate = LED_STABLE_OFF;
+       // nextstate ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+       // bottom_led_set (LED_IDX_MESSAGE, nextstate);
+       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+       // ctr = 65000;
+       // while (ctr > 0) {
+       //      ctr--;
+       // }
+       //ULTIMATELY// nextstate ^= LED_STABLE_ON ^ LED_STABLE_OFF;
+       //ULTIMATELY// bottom_led_set (LED_IDX_MESSAGE, nextstate);
+       // bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+       // bottom_timer_set (exptime + TIME_MSEC(1500));
+}
+
+void complete_top_main (void) {
+       timing_t nextirq;
+       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON);
+       nextirq = bottom_time () + TIME_MSEC(1500);
+       busy = true;
+       // bottom_timer_set (nextirq);
+       // bottom_critical_region_end ();
+       while (true) {
+               if (busy) {
+                       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+               } else {
+                       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+               }
+       }
+}
+
diff --git a/src/function/sip6phone/topmain.c b/src/function/sip6phone/topmain.c
new file mode 100644 (file)
index 0000000..0eaea56
--- /dev/null
@@ -0,0 +1,22 @@
+
+
+/* The main operational loop for the CPU.  Try to run code, and when
+ * nothing remains to be done, stop to wait for interrupts.
+ */
+void top_main (void) {
+       // TODO: init ();
+       netdb_initialise ();
+       // TODO: cpu_add_closure (X);
+       // TODO: cpu_add_closure (Y);
+       // TODO: cpu_add_closure (Z);
+       bottom_critical_region_end ();
+       top_network_online ();  // TODO: Should be called from bottom!
+       while (true) {
+               jobhopper ();
+               bottom_sleep_prepare ();
+               if (cur_prio == CPU_PRIO_ZERO) {
+                       bottom_sleep_commit (SLEEP_SNOOZE);
+               }
+       }
+}
+
index 6423d3f..bd97f89 100644 (file)
@@ -85,24 +85,3 @@ void jobhopper (void) {
        printf ("Jobhopper ends.\n");
 }
 
-
-/* The main operational loop for the CPU.  Try to run code, and when
- * nothing remains to be done, stop to wait for interrupts.
- */
-void top_main (void) {
-       // TODO: init ();
-       netdb_initialise ();
-       // TODO: cpu_add_closure (X);
-       // TODO: cpu_add_closure (Y);
-       // TODO: cpu_add_closure (Z);
-       bottom_critical_region_end ();
-       top_network_online ();  // TODO: Should be called from bottom!
-       while (true) {
-               jobhopper ();
-               bottom_sleep_prepare ();
-               if (cur_prio == CPU_PRIO_ZERO) {
-                       bottom_sleep_commit (SLEEP_SNOOZE);
-               }
-       }
-}
-
index 3980338..5a4d44e 100644 (file)
@@ -286,6 +286,15 @@ bool netcore_bootstrap_step (irq_t *tmrirq) {
                }
        }
        switch (boot_state) {
+       case NCS_DHCPV4:        // A few LAN DHCPv4 attempts
+               if (!have_ipv4 ()) {
+                       get_dhcp4_lease ();
+                       delay = TIME_MSEC(5000);
+                       break;
+               }
+               boot_state = NCS_6BED4;
+               boot_retries = 2;
+               // Continue into NCS_6BED4 for 6bed4 autoconf
        case NCS_6BED4:         // A few 6BED4 attempts over IPv4
                if (!have_ipv6 ()) {
                        ip6binding [0].ip4binding = &ip4binding [0];
@@ -297,21 +306,14 @@ bool netcore_bootstrap_step (irq_t *tmrirq) {
                        return true;
                }
                solicit_router ();
-               delay = 500 * TIME_MSEC;
+               delay = TIME_MSEC(500);
                break;
        case NCS_DHCPV6:        // A few LAN DHCPv6 attempts
                if (have_ipv6 ()) {
                        return true;
                }
                get_dhcp6_lease ();
-               delay = 1000 * TIME_MSEC;
-               break;
-       case NCS_DHCPV4:        // A few LAN DHCPv4 attempts
-               if (have_ipv4 ()) {
-                       return true;
-               }
-               get_dhcp4_lease ();
-               delay = 5000 * TIME_MSEC;
+               delay = TIME_MSEC(1000);
                break;
        case NCS_ONLINE:        // Stable online performance
                return true;
@@ -321,7 +323,7 @@ bool netcore_bootstrap_step (irq_t *tmrirq) {
        case NCS_OFFLINE:       // Await top_network_online()
                break;
        case NCS_PANIC:         // Not able to bootstrap anything
-               // delay = 15 * 60 * TIME_MSEC;
+               // delay = TIME_MIN(15);
                // break;
                return true;
        default:
index 88a29cc..0ba9aaf 100644 (file)
 #include <stdint.h>
 #include <stdbool.h>
 
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
 #include <netinet/icmp6.h>
+#include <netinet/ether.h>
+#include <net/if_arp.h>
 
 #include <config.h>
 
  */
 
 
-/* Declare an efficient network packet analysis function:
+
+/* Analyse incoming network packets.
  *
- * intptr_t netinput (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
- *     ...possibly assembly...
- * }
+ * This is one big switch statement that returns how to
+ * process a packet, or NULL if it is to be dropped.
+ * Instead of proper nesting, which would be a bit
+ * overzealously indented and therefore confusing, a
+ * less structured approach is used, with portions of
+ * the function analysing particular headers and jumping
+ * at such parts of the function with a goto statement.
+ * Surely goto is bad structure, but some situations
+ * really call for it -- like this one.
  *
- * TODO: Check lengths
- * TODO: Verify checksums
+ * The utility functions below _can_ be overridden in
+ * config.h to benefit from the more specific knowledge
+ * for specifically known targets.
  */
-BPF_BEGIN(netinput)
-
-       return NULL;            //TODO// Early bail-out
-
-       STX_MEM (MEM_ETHER_HEAD)                // Store the ethernet header
-       LDW_LEN ()
-       ADD_REX ()
-       STW_MEM (MEM_ALL_DONE)
-
-// IN: ETHER frame at X
-// OUT: ARP, IP4, IP6 frame at X=M[0]
-//
-// netin_ETHER         ldw     #14
-//                     add     x
-//                     tax
-//                     ldh     [x-2]
-//                     jeq     #8100h, .1, .2  ; 802.1Q tag? => step 4 bytes
-// .1                  ldw     #4
-//                     add     x
-//                     tax
-//                     ldh     [x-2]
-// .2                  stx     M[0]
-//                     jeq     #86DDh, netin_IP6_sel, .3
-// .3                  jeq     #0800h, netin_IP4_sel, .4
-// .4                  jeq     #0806h, netin_ARP_sel, netin_DROP
-
-       LDW_LIT (14)
-       ADD_REX ()
-       LDX_ACC ()
-       LDH_IDX (-2)
-       JNE_LIT (0x8100, _ether_1)
-       LDW_LIT (4)
-       ADD_REX ()
-       LDX_ACC ()
-       LDH_IDX (-2)
-BPF_LABEL (_ether_1)
-       STX_MEM (MEM_ETHER_PLOAD)
-       JEQ_LIT (0x86dd, netin_IP6_sel)
-       JEQ_LIT (0x0800, netin_IP4_sel)
-       JEQ_LIT (0x0806, netin_ARP_sel)
-       JMP_ALW (netin_DROP)
-
-
-// IN: ARP frame at X=M[0]
-// RET: ARP fn with frame in M[0], IPv4 src addr in M[1], IPv4 dst addr in M[2]
-//
-// netin_ARP_sel       ldh     [x+2]                   ; protocol type
-//                     jeq     #0800h, .1, netin_DROP  ; check IPv4
-// .1                  ld      [x+4]                   ; hwalen, protalen, cmd
-//                     stx     M[0]
-//                     jeq     #06040001, netin_ARPREQ, .2
-// .2                  jeq     #06040002, netin_ARPREPLY, netin_DROP
-// netin_ARPREQ                return  #net_arp_request
-// netin_ARPREPLY      return  #net_arp_reply
-
-BPF_LABEL(netin_ARP_sel)
-       STX_MEM (MEM_ARP_HEAD)
-       LDH_IDX (2)
-       JNE_LIT (0x0800, netin_DROP)
-       LDW_IDX (4)
-       JEQ_LIT (0x06040001, netin_ARPREQ)
-       JEQ_LIT (0x06040002, netin_ARPREPLY)
-       JMP_ALW (netin_DROP)
-BPF_LABEL(netin_ARPREPLY)
-       LDW_IDX (14)
-       STW_MEM (MEM_IP4_SRC)
-       LDW_IDX (24)
-       STW_MEM (MEM_IP4_DST)
-       RET_LIT (net_arp_reply)
-BPF_LABEL(netin_ARPREQ)
-       LDW_IDX (14)
-       STW_MEM (MEM_IP4_SRC)
-       LDW_IDX (24)
-       STW_MEM (MEM_IP4_DST)
-       RET_LIT (netreply_arp_query)
-
-
-// IN: IP4 frame at X=M[0]
-// OUT: UDP4, ICMP4 at X+20=M[3]; M[1]=src.IP4, M[2]=dst.IP4
-// Assumption: No IPv4 option headers
-//
-// netin_IP4_sel       ldb     [x]                     ; version/headerlen
-//                     jeq     #45h, .1, netin_DROP
-// .1                  ld      [x+12]                  ; src.IP4
-//                     st      M[1]
-//                     ld      [x+16]                  ; dst.IP4
-//                     st      M[2]
-//                     ldx     #20
-//                     add     x
-//                     st      M[3]                    ; IP4 payload address
-//                     tax
-//                     ldb     [x-20+9]                ; payload protocol
-//                     jeq     #17, netin_UDP4_sel, .2
-// .2                  jeq     #1, netin_ICMP4_sel, netin_DROP
-
-BPF_LABEL(netin_IP4_sel)
-       STX_MEM (MEM_IP4_HEAD)
-       LDB_IDX (0)
-       JNE_LIT (0x0045, netin_DROP)
-       LDW_IDX (12)
-       STW_MEM (MEM_IP4_SRC)
-       LDW_IDX (16)
-       STW_MEM (MEM_IP4_DST)
-       LDW_LIT (20)
-       ADD_REX ()
-       STW_MEM (MEM_IP4_PLOAD)
-       LDX_ACC ()
-       LDB_IDX (-20+9)
-       JEQ_LIT (17, netin_UDP4_sel)
-       JEQ_LIT (1, netin_ICMP4_sel)
-       JMP_ALW (netin_DROP)
-
-
-// IN: ICMP4 frame at X=M[3]
-// OUT: TODO
-//
-// netin_ICMP4_sel     TODO
-
-BPF_LABEL(netin_ICMP4_sel)
-       STX_MEM (MEM_ICMP4_HEAD)
-       LDH_IDX (0)     // type/code
-       JEQ_LIT (8 << 8, netin_ICMP4_ping)
-       RET_LIT (0)
-
-BPF_LABEL(netin_ICMP4_ping)
-       RET_LIT (netreply_icmp4_echo_req)
-
 
-// IN: UDP4 frame at X=M[3]
-// OUT: 6BED4, DHCP4 at X+20+8=M[5]; M[4]=src.PORT|dst.PORT
-//
-// netin_UDP4_sel      ld      #8
-//                     add     x
-//                     st      M[5]
-//                     ld      [x]             ; src.PORT|dst.PORT
-//                     st      M[4]
-//                     jeq     #0e450e45h, netin_6BED4_sel, .1
-// .1                  jeq     #4344h, netin_DHCP4_sel, .2
-// .2                  and     #ffff0000h
-//                     jeq     #00350000h, netin_DNS_sel, netin_DROP
-
-BPF_LABEL(netin_UDP4_sel)
-       STX_MEM (MEM_UDP4_HEAD)
-       LDW_LIT (8)
-       ADD_REX ()
-       LDX_ACC ()
-       STX_MEM (MEM_UDP4_PLOAD)
-       LDW_IDX (-8)
-       STW_MEM (MEM_UDP4_PORTS)
-       JEQ_LIT (0x0e450e45, netin_6BED4_sel)
-       JEQ_LIT (0x00430044, netin_DHCP4_sel)
-       AND_LIT (0xffff0000)
-       JEQ_LIT (0x00350000, netin_DNS_sel)
-       JMP_ALW (netin_DROP)
-
-
-// IN: DHCP4 frame at X=M[5]
-// OUT: Returns one of netreply_dhcp4_offer, netdb_dhcp4_ack, netdb_dhcp4_nak
-
-BPF_LABEL(netin_DHCP4_sel)
-       STX_MEM (MEM_DHCP4_HEAD)
-       LDW_LIT (236 + 4)
-       ADD_REX ()
-       LDX_ACC ()
-       LDW_IDX (-4)    // Magic cookie check
-       JNE_LIT (0x63825363, netin_DROP)
-BPF_LABEL(netin_DHCP4_optparse)
-       LDB_IDX (0)
-       JEQ_LIT (255, netin_DROP)
-       JEQ_LIT (0, netin_DHCP4_padding)
-       JNE_LIT (53, netin_DHCP4_optskip)
-       LDB_IDX (2)
-       JEQ_LIT (2, netin_DHCP4_offer)
-       JEQ_LIT (5, netin_DHCP4_ack)
-       JEQ_LIT (6, netin_DHCP4_nak)
-       JMP_ALW (netin_DROP)    // Including for my b'casted DHCP4 discover
-BPF_LABEL(netin_DHCP4_padding)
-       LDW_LIT (1)
-       ADD_REX ()
-       LDX_ACC ()
-       JMP_ALW (netin_DHCP4_optparse)
-BPF_LABEL(netin_DHCP4_optskip)
-       AND_LIT (0xff)
-       ADD_LIT (2)
-       ADD_REX ()
-       LDX_ACC ()
-       JMP_ALW (netin_DHCP4_optparse)
-BPF_LABEL(netin_DHCP4_offer)
-       RET_LIT (netreply_dhcp4_offer)
-BPF_LABEL(netin_DHCP4_ack)
-       RET_LIT (netdb_dhcp4_ack)
-BPF_LABEL(netin_DHCP4_nak)
-       RET_LIT (netdb_dhcp4_nak)
-
-
-// IN: 6BED4 frame at X=M[5]
-// OUT: IP6 at X=M[6]
-// Note: M[1]=src.IP, M[2]=dst.IP, M[3]=IP4, M[4]=src.PORT|dst.PORT all nonzero
-//
-// netin_6BED4_sel     ldx     M[5]            ; decapsulate IP6 package
-//                     jmp     netin_IP6_sel_anysrc
-
-BPF_LABEL(netin_6BED4_sel)
-       STX_MEM (MEM_UDP4_PLOAD)
-       STX_MEM (MEM_6BED4_PLOAD)
-       JMP_ALW (netin_IP6_sel_anysrc)
-
-
-// IN: IP6 frame at X
-// OUT: IP6 frame at X=M[6], UDP6 or ICMP6 at X+40
-//
-// netin_IP6_sel       ld      #0
-//                     st      M[1]            ; no src.IP4
-//                     st      M[2]            ; no dst.IP4
-//                     st      M[3]            ; no IP4 payload
-//                     st      M[4]            ; no UDP4 src.PORT|dst.PORT
-// netin_IP6sel__anysrc        stx     M[6]            ; IP6 frame
-//                     ldb     [x+0]           ; version/trafficclass
-//                     and     #f0h            ; version/0
-//                     jeq     #60h, .1, netin_DROP
-// .1                  ldb     [x+6]           ; next header
-//                     jeq     #17, netin_UDP6_sel, .2
-// .2                  jeq     #58, netin_ICMP6_sel, netin_DROP
-
-BPF_LABEL(netin_IP6_sel)
-#if 0
-       LDW_LIT (0)
-       STW_MEM (MEM_IP4_SRC)
-       STW_MEM (MEM_IP4_DST)
-       STW_MEM (MEM_IP4_PLOAD)
-       STW_MEM (MEM_UDP4_PLOAD)
+#define forward(t) here += sizeof (t); fromhere -= sizeof (t);
+#define store(i, t) if (fromhere < sizeof (t)) return NULL; mem [i] = (t *) here;
+#define store_forward(i, t) store(i,t) forward(t)
+#ifndef get08
+#  define get08(o) (here [o])
+#endif
+#ifndef get16
+#  define get16(o) ((here [o] << 8) | here [o+1])
+#endif
+#ifndef get32
+#  define get32(o) ((here [o] << 24) | (here [o+1] << 16) | (here [o+2] << 8) | here [o+3])
 #endif
-BPF_LABEL(netin_IP6_sel_anysrc)
-       STX_MEM (MEM_IP6_HEAD)
-       LDB_LIT (40)
-       ADD_REX ()
-       LDX_ACC ()
-       STX_MEM (MEM_IP6_PLOAD)
-       LDB_IDX (-40)
-       AND_LIT (0xf0)
-       JNE_LIT (0x60, netin_DROP)
-       LDB_IDX (-40+6)
-       JEQ_LIT (17, netin_UDP6_sel)
-       JEQ_LIT (58, netin_ICMP6_sel)
-       JMP_ALW (netin_DROP)
-
-
-// IN: ICMP6 at X
-// OUT: TODO
-//
-// netin_ICMP6_sel: switch between alternative message types
-
-BPF_LABEL(netin_ICMP6_sel)
-       STX_MEM (MEM_ICMP6_HEAD)
-       LDH_IDX (0)     // Fetch type, code
-       // Ignore ND_ROUTER_SOLICIT  << 8, netin_ICMP6_ROUTER_SOLICIT
-       JEQ_LIT (ND_ROUTER_ADVERT    << 8, netin_ICMP6_ROUTER_ADVERT)
-       JEQ_LIT (ND_NEIGHBOR_SOLICIT << 8, netin_ICMP6_NEIGHBOUR_SOLICIT)
-       JEQ_LIT (ND_NEIGHBOR_ADVERT  << 8, netin_ICMP6_NEIGHBOUR_ADVERT)
-       //TODO//JEQ_LIT (ND_REDIRECT << 8, netin_ICMP6_REDIRECT)
-       JEQ_LIT (ICMP6_ECHO_REQUEST  << 8, netin_ICMP6_ECHO_REQUEST)
-       JEQ_LIT (ICMP6_ECHO_REPLY    << 8, netin_ICMP6_ECHO_REPLY)
-       JMP_ALW (netin_DROP)
-
-BPF_LABEL(netin_ICMP6_ROUTER_ADVERT)
-       RET_LIT (netdb_router_advertised)
-
-// ND Neighbour Solicitation:
-// If aimed at me, respond automatically with Neigbour Advertisement
-BPF_LABEL(netin_ICMP6_NEIGHBOUR_SOLICIT)
-       RET_LIT (netreply_icmp6_ngb_disc)
-
-BPF_LABEL(netin_ICMP6_NEIGHBOUR_ADVERT)
-       RET_LIT (netdb_neighbour_advertised)
-
-BPF_LABEL(netin_ICMP6_ECHO_REQUEST)
-       RET_LIT (netreply_icmp6_echo_req)
-
-BPF_LABEL(netin_ICMP6_ECHO_REPLY)
-       JMP_ALW (netin_DROP)    // TODO: Process if it is used for tests?
-
-
-// IN: UDP6 at X
-// OUT: RTP, RTCP, SIP, DHCP6, DNS, DNS_SD at X=M[8]; M[7]=src.PORT|dst.PORT
-// Note: RTP/RTCP is located at ports 8192..65535
-//
-// netin_UDP6_sel      ld      #48
-//                     add     x
-//                     st      M[8]
-//                     tax
-//                     ld      [x-8+0]                 ; src.PORT|dst.PORT
-//                     jset    #0000e000h, .1, .3      ; RTP/RTCP or other?
-// .1                  jset    #00000001h, netin_RTCP_sel, netin_RTP_sel
-// .2                  jeq     #02230222h, netin_DHCP6_sel, .3
-// .3                  and     #0000ffffh              ; dst.PORT
-//                     jeq     #5060, netin_SIP_sel, .4
-// .4                  jeq     #5353, netin_DNS_SD_sel, .5
-// .5                  jeq     #53, netin_DNS_sel, netin_DROP
-
-BPF_LABEL(netin_UDP6_sel)
-       STX_MEM (MEM_UDP6_HEAD)
-       LDW_LIT (8)
-       ADD_REX ()
-       STW_MEM (MEM_UDP6_PLOAD)
-       LDX_ACC ()
-       LDW_IDX (-8+0)
-       STW_MEM (MEM_UDP6_PORTS)
-       JMZ_LIT (0x0000e000, _UDP6_2)
-       JMZ_LIT (0x00000001, netin_RTCP_sel)
-       JMP_ALW (netin_RTP_sel)
-BPF_LABEL(_UDP6_2)
-       AND_LIT (0x0000ffff)
-       JEQ_LIT (546, netin_DHCP6_sel)
-       JEQ_LIT (5060, netin_SIP_sel)
-       JEQ_LIT (5353, netin_DNS_SD_sel)
-       JEQ_LIT (53, netin_DNS_sel)
-       JMP_ALW (netin_DROP)
-
-
-// IN: RTP at M[8]=X
-// OUT: net_rtp
-//
-// netin_RTP_sel       return  #net_rtp
-
-BPF_LABEL(netin_RTP_sel)
-       STX_MEM (MEM_RTP_HEAD)
-       RET_LIT (net_rtp)
-
-
-// IN: RTCP at M[8]=X
-// OUT: net_rtcp
-//
-// netin_RTCP_sel      return  #net_rtcp
-
-BPF_LABEL(netin_RTCP_sel)
-       STX_MEM (MEM_RTCP_HEAD)
-       RET_LIT (net_rtcp)
-
-
-// IN: SIP at M[8]=X
-// OUT: net_sip
-//
-// netin_SIP_sel       return  #net_sip
-
-BPF_LABEL(netin_SIP_sel)
-       STX_MEM (MEM_SIP_HEAD)
-       RET_LIT (net_sip)
-
-
-// IN: DHCP6 at M[8]=X
-// OUT: TODO
-
-BPF_LABEL(netin_DHCP6_sel)
-       STX_MEM (MEM_DHCP6_HEAD)
-       LDB_IDX (0)
-       JEQ_LIT (2, netin_DHCP6_advertise)
-       JEQ_LIT (7, netin_DHCP6_reply)
-       JNE_LIT (10, netin_DROP)
-BPF_LABEL(netin_DHCP6_reconfigure)
-       RET_LIT (netdb_dhcp6_reconfigure)
-BPF_LABEL(netin_DHCP6_reply)
-       RET_LIT (netdb_dhcp6_reply)
-BPF_LABEL(netin_DHCP6_advertise)
-       RET_LIT (netreply_dhcp6_advertise)
-
-
-// IN: DNS at M[8]=X
-// OUT: TODO
-
-BPF_LABEL(netin_DNS_sel)
-       STX_MEM (MEM_DNS_HEAD)
-       RET_LIT (0)
-
-
-// IN: DNS_SD at M[8]=X
-// OUT: TODO: Nogal wat gegokt over hoe MDNS/DNS_SD werkt
-//
-// netin_DNS_SD_sel    ldh     [x+2]
-//                     jset    #8000h, .resp, .query
-//
-// .resp               jset    #0203h, .resp.ko, .resp.ok   ; TC or RC!=OK
-// .resp.ko            return  #net_mdns_resp_error
-// .resp.ok            jset    #0400h, .resp.dyn, .resp.std
-// .resp.dyn           return  #net_mdns_resp_dyn
-// .resp.std           return  #net_mdns_resp_std
-//
-// .query              xor     #2000h  ; std query flag
-//                     jset    #3c00h, .query.ko, .query.ok
-// .query.ko           return  #net_mdns_query_error
-// .query.ok           return  #net_mdns_query_ok
-
-BPF_LABEL(netin_DNS_SD_sel)
-       STX_MEM (MEM_DNSSD_HEAD)
-       LDH_IDX (2)
-       JMZ_LIT (0x8000, _DNS_query)
-       JMZ_LIT (0x0203, _DNS_resp_ok)
-       RET_LIT (net_mdns_resp_error)
-BPF_LABEL(_DNS_resp_ok)
-       JMZ_LIT (0x0400, _DNS_resp_std)
-       RET_LIT (net_mdns_resp_dyn)
-BPF_LABEL(_DNS_resp_std)
-       RET_LIT (net_mdns_resp_std)
-
-BPF_LABEL(_DNS_query)
-       XOR_LIT (0x2000)
-       JMZ_LIT (0x3c00, _DNS_query_ok)
-       RET_LIT (net_mdns_query_error)
-BPF_LABEL(_DNS_query_ok)
-       RET_LIT (net_mdns_query_ok)
-
-
-// Note: Return a panic result, intending to cause a silent frame drop.
-//       No explicitly communicated error message should jump here, only
-//       frames that match no known pattern should end up here.
-//
-// netin_DROP          return  #0                      ; request frame drop
-
-BPF_LABEL(netin_DROP)
-       RET_LIT (0)
-
-
-// End of the BPF-styled assembly code
-//
-BPF_END()
 
+intptr_t netinput (uint8_t *pkt, uint16_t pktlen, intptr_t *mem) {
+
+       register uint8_t *here = pkt;
+       register uint16_t fromhere = pktlen;
+
+       //
+       // Store the end of the entire packet
+       mem [MEM_ALL_DONE] = &pkt [pktlen];
+
+       //
+       // Store the ethernet header
+       uint16_t ethertp = get16 (12);
+       if (ethertp == 0x8100) {
+               struct ethhdrplus { struct ethhdr std; uint8_t ext8021q [4]; };
+               store_forward (MEM_ETHER_HEAD, struct ethhdrplus);
+               ethertp = get16 (16);
+       } else {
+               store_forward (MEM_ETHER_HEAD, struct ethhdr);
+       }
+       //
+       // Jump, depending on the ethernet type
+       switch (ethertp) {
+       case 0x86dd: goto netin_IP6_sel;
+       case 0x0800: goto netin_IP4_sel;
+       case 0x0806: goto netin_ARP_sel;
+       default: return NULL;
+       }
+
+       //
+       // Accept ARP reply and query messages translating IPv4 to MAC
+       uint16_t arpproto;
+netin_ARP_sel:
+       arpproto = get16 (2);
+       if (arpproto != 0x0800) return NULL;
+       store (MEM_ARP_HEAD, struct arphdr);
+       mem [MEM_IP4_SRC] = get32 (14);
+       mem [MEM_IP4_DST] = get32 (24);
+       uint32_t arpdetails = get32 (4);
+       //
+       // Decide what to return based on the ARP header contents
+       switch (arpdetails) {
+       case 0x06040001: return net_arp_reply;
+       case 0x06040002: return net_arp_query;
+       default: return NULL;
+       }
+
+       //
+       // Decide what IPv4 protocol has come in
+netin_IP4_sel:
+       store (MEM_IP4_HEAD, struct iphdr);
+       if (get08 (0) != 0x45) return NULL;
+       mem [MEM_IP4_SRC] = get32 (12);
+       mem [MEM_IP4_DST] = get32 (15);
+       uint8_t ip4_ptype = get08 (9);
+       forward (struct iphdr);
+       mem [MEM_IP4_PLOAD] = here;
+       //
+       // Jump to a handler for the payload type
+       switch (ip4_ptype) {
+       case 17: goto netin_UDP4_sel;
+       case 1:  goto netin_ICMP4_sel;
+       default: return NULL;
+       }
+
+       //
+       // Decide how to handle ICMP4
+       uint16_t icmp4_type_code;
+netin_ICMP4_sel:
+       icmp4_type_code = get16 (0);
+       switch (icmp4_type_code) {
+       case 8 << 8: return netreply_icmp4_echo_req;
+       default: return NULL;
+       }
+
+       //
+       // Decide how to handle UDP4
+netin_UDP4_sel:
+       store (MEM_UDP4_HEAD, struct udphdr);
+       uint16_t udp4_src = mem [MEM_UDP4_SRC_PORT] = get16 (0);
+       uint16_t udp4_dst = mem [MEM_UDP4_DST_PORT] = get16 (2);
+       forward (struct udphdr);
+       mem [MEM_UDP4_PLOAD] = here;
+       //
+       // Choose a handler based on port
+       if (udp4_src == 3653) goto netin_6BED4_sel;
+       if ((udp4_src == 67) && (udp4_dst == 68)) goto netin_DHCP4_sel;
+       if (udp4_dst == 53) goto netin_DNS_sel;
+       return NULL;
+
+       //
+       // Handle incoming DHCP4 traffic
+netin_DHCP4_sel:
+       store (MEM_DHCP4_HEAD, uint8_t);
+       if (fromhere < 236 + 4) return NULL;
+       uint32_t dhcp4_magic_cookie = get32 (236);
+       if (dhcp4_magic_cookie != 0x63825363) return NULL;      // TODO: BOOTP?
+       here     += 236 + 4;
+       fromhere -= 236 + 4;
+       //
+       // Parse DHCP4 options
+       while (true) {
+               uint8_t dhcp4_option = get08 (0);
+               if (dhcp4_option != 0) {
+                       if (2 + get08 (1) > fromhere) {
+                               return NULL;
+                       }
+               }
+               switch (dhcp4_option) {
+               case 255: // Termination, not run into an offer
+                       return NULL;
+               case 0: // Padding
+                       here++;
+                       continue;
+               case 53: // DHCP4_offer
+                       switch (get08 (2)) {
+                       case 2: return netreply_dhcp4_offer;
+                       case 5: return netdb_dhcp4_ack;
+                       case 6: return netdb_dhcp4_nak;
+                       default: return NULL;
+                       }
+               default:
+                       here += 2 + here [1];
+                       break;
+               }
+       }
+
+       //
+       // Handling 6BED4 tunnelled traffic
+netin_6BED4_sel:
+       mem [MEM_6BED4_PLOAD] = mem [MEM_UDP4_PLOAD];
+       // Code follows immediately below: goto netin_IP6_sel;
+
+       //
+       // Handle incoming IP6 traffic
+netin_IP6_sel:
+       if ((get08 (0) & 0xf0) != 0x60) return NULL;
+       store (MEM_IP6_HEAD, struct ip6_hdr);
+       uint8_t ip6_nxthdr = get08 (6);
+       forward (struct ip6_hdr);
+       store (MEM_IP6_PLOAD, uint8_t);
+       //
+       // Choose a handler based on the next header
+       switch (ip6_nxthdr) {
+       case 17: goto netin_UDP6_sel;
+       case 58: goto netin_ICMP6_sel;
+       default: return NULL;
+       }
+
+       //
+       // Hande incoming ICMP6 traffic
+netin_ICMP6_sel:
+       store (MEM_ICMP6_HEAD, struct icmp6_hdr);
+       uint16_t icmp6_type_code = get16 (0);
+       switch (icmp6_type_code) {
+       case ND_ROUTER_ADVERT << 8:     return (fromhere < 16)? NULL: netdb_router_advertised;
+       case ND_NEIGHBOR_SOLICIT << 8:  return (fromhere < 24)? NULL: netreply_icmp6_ngb_disc;
+       case ND_NEIGHBOR_ADVERT << 8:   return (fromhere < 24)? NULL: netdb_neighbour_advertised;
+       case ND_REDIRECT << 8:          return (fromhere < 40)? NULL: NULL; /* TODO */
+       case ICMP6_ECHO_REQUEST << 8:   return (fromhere <  8)? NULL: netreply_icmp6_echo_req;
+       case ICMP6_ECHO_REPLY << 8:     return (fromhere <  8)? NULL: NULL; /* Future option */
+       default: return NULL;
+       }
+
+       //
+       // Decide how to handle incoming UDP6 traffic
+netin_UDP6_sel:
+       store (MEM_UDP6_HEAD, struct udphdr);
+       mem [MEM_UDP6_PLOAD] = here + sizeof (struct udphdr);
+       uint16_t udp6_src = mem [MEM_UDP6_SRC_PORT] = get16 (0);
+       uint16_t udp6_dst = mem [MEM_UDP6_DST_PORT] = get16 (2);
+       here += sizeof (struct udphdr);
+       //
+       // Port mapping:
+       // udp6_dst >= 0x4000 are RTP (even ports) or RTCP (odd ports)
+       // udp6_dst == 546    is DHCP6
+       // udp6_dst == 5060   is SIP
+       // udp6_dst == 5353   is DNS-SD
+       // udp6_dst == 53     is DNS
+       if (udp6_dst >= 0x4000) {
+               if (udp6_dst & 0x0001) {
+                       mem [MEM_RTP_HEAD] = here;
+                       return net_rtp;
+               } else {
+                       return net_rtcp;
+               }
+       } else if (udp6_dst == 5060) {
+               mem [MEM_SIP_HEAD] = here;
+               return net_sip;
+       } else if (udp6_dst == 5353) {
+               goto netin_DNSSD_sel;
+       } else if (udp6_dst == 53) {
+               goto netin_DNS_sel;
+       } else if (udp6_dst == 546) {
+               goto netin_DHCP6_sel;
+       } else {
+               return NULL;
+       }
+       
+
+netin_DHCP6_sel:
+       store (MEM_DHCP6_HEAD, uint8_t);
+       uint8_t dhcp6_tag = *here;
+       switch (dhcp6_tag) {
+       case 2: return netreply_dhcp6_advertise;
+       case 7: return netdb_dhcp6_reply;
+       case 10: return netdb_dhcp6_reconfigure;
+       default: return NULL;
+       }
+
+netin_DNS_sel:
+       store (MEM_DNS_HEAD, uint8_t);
+       return NULL;    // TODO: Actually, split/process DNS
+
+netin_DNSSD_sel:
+       store (MEM_DNSSD_HEAD, uint8_t);
+       uint16_t dnssd_flags = get16 (2);
+       if (dnssd_flags & 0x8000) {
+               // Response
+               if (dnssd_flags & 0x0203) {
+                       return net_mdns_resp_error;
+               } else if (dnssd_flags & 0x0400) {
+                       return net_mdns_resp_dyn;
+               } else {
+                       return net_mdns_query_ok;
+               }
+       } else {
+               // Query
+               if ((dnssd_flags ^ 0x2000) & 0x3c00) {
+                       return net_mdns_query_error;
+               } else {
+                       return net_mdns_query_ok;
+               }
+       }
+
+       // Finally, a catchall that rejects anything that makes it to here
+       return NULL;
+}
index 3db4bcb..aff0eb6 100644 (file)
@@ -72,7 +72,7 @@ uint8_t *netreply_ip4 (uint8_t *pout, intptr_t *mem) {
        ip4out->frag_off = htons (0x4000);      // Don't fragment
        ip4out->saddr = ip4in->daddr;
        ip4out->daddr = ip4in->saddr;
-       mem [MEM_IP4_HEAD] = (uint32_t) ip4out;
+       mem [MEM_IP4_HEAD] = (uintptr_t) ip4out;
        return &pout [sizeof (struct iphdr)];
 }
 
@@ -82,8 +82,8 @@ uint8_t *netreply_ip4 (uint8_t *pout, intptr_t *mem) {
 uint8_t *netreply_udp4 (uint8_t *pout, intptr_t *mem) {
        pout = netreply_ip4 (pout, mem);
        struct udphdr *udp = (struct udphdr *) pout;
-       udp->source = htons (mem [MEM_UDP4_PORTS] & 0xffff);
-       udp->dest   = htons (mem [MEM_UDP4_PORTS] >> 16);
+       udp->source = htons (mem [MEM_UDP4_DST_PORT]);
+       udp->dest   = htons (mem [MEM_UDP4_SRC_PORT]);
        mem [MEM_UDP4_HEAD] = (intptr_t) udp;
        return &pout [sizeof (struct udphdr)];
 }
@@ -95,7 +95,7 @@ uint8_t *netreply_udp4_6bed4 (uint8_t *pout, intptr_t *mem) {
        mem [MEM_IP4_SRC] = htonl (ip4_6bed4);
        pout = netreply_ip4 (pout, mem);
        struct udphdr *udp = (struct udphdr *) pout;
-       udp->source = htons (mem [MEM_UDP4_PORTS] & 0xffff);
+       udp->source = htons (mem [MEM_UDP4_DST_PORT]);
        udp->dest   = htons (3653);
        mem [MEM_6BED4_PLOAD] =
        mem [MEM_UDP4_HEAD] = (intptr_t) udp;
@@ -129,8 +129,8 @@ uint8_t *netreply_ip6 (uint8_t *pout, intptr_t *mem) {
 uint8_t *netreply_udp6 (uint8_t *pout, intptr_t *mem) {
        pout = netreply_ip6 (pout, mem);
        struct udphdr *udp = (struct udphdr *) pout;
-       udp->source = htons (mem [MEM_UDP6_PORTS] & 0xffff);
-       udp->dest   = htons (mem [MEM_UDP6_PORTS] >> 16);
+       udp->source = htons (mem [MEM_UDP6_DST_PORT]);
+       udp->dest   = htons (mem [MEM_UDP6_SRC_PORT]);
        mem [MEM_UDP6_HEAD] = (intptr_t) udp;
        return &pout [sizeof (struct udphdr)];
 }
index 465375e..4fcf4c5 100644 (file)
@@ -129,8 +129,8 @@ uint8_t *netsend_udp4 (uint8_t *pout, intptr_t *mem) {
        // TODO: Setup MEM_ETHER_DST with router's address
        pout = netsend_ip4 (pout, mem);
        struct udphdr *udp = (struct udphdr *) pout;
-       udp->source = htons (mem [MEM_UDP4_PORTS] & 0xffff);
-       udp->dest   = htons (mem [MEM_UDP4_PORTS] >> 16);
+       udp->source = htons (mem [MEM_UDP4_SRC_PORT]);
+       udp->dest   = htons (mem [MEM_UDP4_DST_PORT]);
        mem [MEM_UDP4_HEAD] = (intptr_t) udp;
        return &pout [sizeof (struct udphdr)];
 }
@@ -182,8 +182,8 @@ uint8_t *netsend_udp6 (uint8_t *pout, intptr_t *mem) {
        // TODO: Setup MEM_ETHER_DST with router's address
        pout = netsend_ip6 (pout, mem);
        struct udphdr *udp = (struct udphdr *) pout;
-       udp->source = htons (mem [MEM_UDP6_PORTS] & 0xffff);
-       udp->dest   = htons (mem [MEM_UDP6_PORTS] >> 16);
+       udp->source = htons (mem [MEM_UDP6_SRC_PORT]);
+       udp->dest   = htons (mem [MEM_UDP6_DST_PORT]);
        mem [MEM_UDP6_HEAD] = (intptr_t) udp;
        return &pout [sizeof (struct udphdr)];
 }
@@ -238,7 +238,8 @@ uint8_t *netsend_icmp6_ngb_sol (uint8_t *pout, intptr_t *mem) {
 /* Send a DHCPv4 DISCOVER packet to initiatie IPv4 LAN configuration.
  */
 uint8_t *netsend_dhcp4_discover (uint8_t *pout, intptr_t *mem) {
-       mem [MEM_UDP4_PORTS] = 0x00430044;
+       mem [MEM_UDP4_SRC_PORT] = 68;
+       mem [MEM_UDP4_DST_PORT] = 67;
        mem [MEM_IP4_DST] = 0xffffffff;
        mem [MEM_ETHER_DST] = (intptr_t) ether_broadcast;
        pout = netsend_udp4 (pout, mem);
@@ -273,7 +274,8 @@ uint8_t *netsend_dhcp4_discover (uint8_t *pout, intptr_t *mem) {
 /* Send a DHCPv6 SOLICIT packet to initiatie native IPv6 configuration.
  */
 uint8_t *netsend_dhcp6_solicit (uint8_t *pout, intptr_t *mem) {
-       mem [MEM_UDP6_PORTS] = 0x02230222;
+       mem [MEM_UDP6_SRC_PORT] = 546;
+       mem [MEM_UDP6_DST_PORT] = 547;
        mem [MEM_BINDING6] = (intptr_t) binding_linklocal;
        mem [MEM_IP6_DST] = (intptr_t) ip6_multicast_all_dhcp6_servers;
        mem [MEM_ETHER_DST] = (intptr_t) ether_multicast_all_dhcp6_servers;
index b0e84a4..55c5368 100644 (file)
@@ -36,7 +36,7 @@ static bool zero_timeout (irq_t irq) {
  * time and then fall asleep.
  */
 void zero_start (void) {
-       timer_start (&zero_sleeptimer, 60 * TIME_SEC, zero_timeout);
+       timer_start (&zero_sleeptimer, TIME_MIN(1), zero_timeout);
 }
 
 
index f81a0ac..b7ae336 100644 (file)
 #
 
 
-mainmenu "Configuration for firmly.0cpm SIP telephony"
+mainmenu "Configure 0cpm Firmerware for SIP telephony"
 
-choice
-       prompt "Target platform"
-       default TARGET_LINUX_RAWSOCK
+# 0. Meta configuration
+source "src/target/Kconfig.meta"
 
-config TARGET_AVM_FRITZBOX
-       depends on TODO_IMPLEMENT_FIRST
-       bool "AVM Fritz!Box"
-       help
-         Depending on the model, AVM Fritz!Box can use any of a variety
-         of telephony chips.  The firmware will build a program that
-         can be incorporated into Freetz (see http://freetz.org/ for
-         details).
+# 1. Brand selection
+source "src/target/Kconfig.brand"
 
-# config TARGET_GRANDSTREAM_HANDYTONE
-# config TARGET_GRANDSTREAM_BUDGETONE
-# config TARGET_GRANDSTREAM_GXP
+# 2. Model within brand
+source "src/target/Kconfig.model"
 
-# config TARGET_LINKSYS_SPA3000
-# config TARGET_LINKSYS_SPA9xx
-
-config TARGET_LINUX_RAWSOCK
-       depends on TODO_IMPLEMENT_FIRST
-       bool "Linux desktop"
-       select TARGET_POSIX_RAWSOCK
-       help
-         This is a platform intended to run on the same platform as
-         used for building.  It is built on a raw socket, so it does
-         not require IPv6 support in the kernel.  It will obtain its
-         own network leases, so it should be tested for non-interference
-         if any other software is run on the same platform.
-
-         Once built, run the command src/target/rawsock/firmly0cpm.bin
-         on your current platform.  It will configure itself automatically.
-
-         TODO: sound devices?  keyboard?  display?
-
-         TODO: Demo entry. Not implemented yet.
-
-config TARGET_LINUX_TUNTEST
-       bool "Linux tunnel device"
-       help
-         Test and demonstration target intended for development.
-
-         This creates a tunnel interface behind which the firmly.0cpm
-         firmware is working.  You can route/bridge/filter/simulate
-         the surrounding network in any way you like.
-
-         Once built, run the command src/target/tuntest/firmly0cpm.bin
-         on your current platform.  It will configure itself automatically.
-
-         TODO: sound devices?  keyboard?  display?
-
-config TARGET_SIEMENS_GIGASET
-       depends on TODO_IMPLEMENT_FIRST
-       bool "Siemens Gigaset xnnnIP"
-       help
-         The Siemens Gigaset platform has DECT/SIP phones with numbers
-         like C470IP or A580IP.  Important in this is the "IP" postfix.
-         There has been a short-lived clone from Target, the DIP450.
-
-         The platforms contain LGPL-licensed software so they permit
-         uploading new firmware from their web interface.
-
-         Once built, upload src/target/gigaset/firmly0cpm.bin to a
-         webserver and set the firmware location in your phone to the
-         proper URL to migrate to the new platform.
-
-         TODO: Demo entry. Not implemented yet.
-
-config TARGET_SMC_WSP100_DSP200
-       depends on TODO_IMPLEMENT_FIRST
-       bool "SMC WSP100, WSKP100, DSP200"
-       help
-         This covers the wireless models WSP100 and WSKP100, as well
-         as the table model DSP200.  The WSKP100 is a special version
-         that runs Skype, not SIP.  The space in these devices varies.
-
-         This DSP200 seems to resist configuration with any common SIP
-         telephony service.  You can revive the phone by compiling the
-         firmly.0cpm platform for it.
-
-         Once built, install by ...TODO...
-
-         TODO: Demo entry. Not implemented yet.
-
-endchoice
+# 3. Hardware platform for model
+source "src/target/Kconfig.platform"
 
+# 4. Intended functionality
+source "src/function/Kconfig"
 
 source "src/net/Kconfig"
 source "src/phone/Kconfig"
diff --git a/src/target/Kconfig.brand b/src/target/Kconfig.brand
new file mode 100644 (file)
index 0000000..233fc90
--- /dev/null
@@ -0,0 +1,65 @@
+# Manufacturers / brands
+
+choice
+       prompt "1. Hardware manufacturer"
+       default TARGET_GRANDSTREAM
+
+config TARGET_GRANDSTREAM
+       bool "Grandstream"
+       help
+         Grandstream phones, shown on http://www.grandstream.com/
+         are built around Texas Instruments' DSP processor ranges
+         TMS320VC5401 and TMS320VC5501.  You would have to scratch
+         paint off of the DSP before being able to read that, but
+         given the model it is possible to establish the target.
+
+         Reverse engineering information is available on
+         http://devel.0cpm.org/reverse/grandstream/
+
+config TARGET_POSIX
+       bool "POSIX platforms"
+       help
+         Not all firmware runs as a standalone image.  Several run
+         on top of POSIX-compliant platforms like Linux.
+         Select this target to include those platforms.
+
+config TARGET_APPLE
+       bool "Apple"
+       depends on UNIMPLEMENTED
+       help
+         The Apple platforms run on top of Darwin, their own brand of
+         FreeBSD.  This target sets up potential Apple targets.
+
+config TARGET_SIPURA
+       bool "Sipura/Linksys/Cisco SPA"
+       depends on UNIMPLEMENTED
+       help
+
+config TARGET_FRITZBOX
+       bool "AVM Fritz!Box"
+       depends on UNIMPLEMENTED
+       help
+         Depending on the model, AVM Fritz!Box can use any of a variety
+         of telephony chips.  The firmware will build a program that
+         can be incorporated into Freetz (see http://freetz.org/ for
+         details).
+
+config TARGET_GIGASET
+       bool "Siemens Gigaset xnnnIP"
+       depends on UNIMPLEMENTED
+       help
+         The Siemens Gigaset platform has DECT/SIP phones with numbers
+         like C470IP or A580IP.  Important in this is the "IP" postfix.
+         There has been a short-lived clone from Target, the DIP450.
+
+         The platforms contain LGPL-licensed software so they permit
+         uploading new firmware from their web interface.
+
+         Once built, upload src/target/gigaset/firmly0cpm.bin to a
+         webserver and set the firmware location in your phone to the
+         proper URL to migrate to the new platform.
+
+         TODO: Demo entry. Not implemented yet.
+
+endchoice
+
diff --git a/src/target/Kconfig.gigaset b/src/target/Kconfig.gigaset
new file mode 100644 (file)
index 0000000..c170500
--- /dev/null
@@ -0,0 +1,16 @@
+# Siemens/Gigaset phone models
+
+choice
+       prompt "2. Siemens Gigaset phone models"
+       depends on TARGET_GIGASET
+       default TARGET_GIGASET_A580IP
+
+config TARGET_GIGASET_CHAGALL
+       bool "Gigaset A580IP, C470IP, xxxIP"
+       select PLATFORM_ARM
+       select PLATFORM_ARM_BLUEBIRD
+       help
+         Siemens Gigaset is a platform for DECT in general.  The models
+         that end in "IP" are the ones that implement SIP functionality.
+
+endchoice
diff --git a/src/target/Kconfig.grandstream b/src/target/Kconfig.grandstream
new file mode 100644 (file)
index 0000000..31d05ac
--- /dev/null
@@ -0,0 +1,38 @@
+# Grandstream phone models
+
+choice
+       prompt "2. Grandstream phone models"
+       depends on TARGET_GRANDSTREAM
+       default TARGET_GRANDSTREAM_BT20x
+
+config TARGET_GRANDSTREAM_BT10x
+       bool "Budgetone 100, 101, 102"
+       select PLATFORM_TIC54x
+       help
+         Budgetone is the entry-level speaker phone from Grandstream.
+         The older models were numbered 10x, the newer ones are 20x.
+         These older models have one or two 10 Mbps ethernet jacks.
+
+         They look like simple phones, with no line selection facilities
+         beyond a simple flash button.  They do however have buttons for
+         conferences and call transfer and hold.
+
+config TARGET_GRANDSTREAM_BT20x
+       bool "Budgetone 200, 201"
+       select PLATFORM_TIC54x
+       help
+         Budgetone is the entry-level speaker phone from Grandstream.
+         The older models were numbered 10x, the newer ones are 20x.
+         These newer models have one or two 100 Mbps ethernet jacks.
+
+         They look like simple phones, with no line selection facilities
+         beyond a simple flash button.  They do however have buttons for
+         conferences and call transfer and hold.
+
+config TARGET_GRANDSTREAM_GXP20xx
+       bool "GXP 2000, 2010, 2020"
+       depends on UNIMPLEMENTED
+       select PLATFORM_TIC55x
+
+endchoice
+
diff --git a/src/target/Kconfig.meta b/src/target/Kconfig.meta
new file mode 100644 (file)
index 0000000..d092655
--- /dev/null
@@ -0,0 +1,50 @@
+# Meta-configuration
+
+menu "0. Configuration meta parameters"
+
+config DEVEL
+       bool "Show development build options"
+       default n
+       select FUNCTION_DEVEL_NETCONSOLE
+       help
+         Aside from production builds, there are various intermediate
+         settings that are helpful while reverse engineering, testing
+         and debugging.  This option shows those additional builds.
+
+         A few examples of added facilities: very basic programs that
+         basic I/O (hook contact, LED, that sort of thing) without
+         assuming a network driver; network driver testing; and of
+         course debugging output to a platform's console interface.
+
+         Select this option if you are developing on the 0cpm firmerware.
+
+config UNIMPLEMENTED
+       bool "Include incomplete build options"
+       depends on DEVEL
+       default n
+       help
+         This option selects platforms and options whose development
+         has not yet been completed.
+
+         Select this option while developing on such incomplete code.
+         It is possible to checkin such code as long as the Kconfig
+         options include "depends on UNIMPLEMENTED"
+
+config PLATFORM_PREFIX
+       string "Toolchain prefix directory"
+       default ""
+
+config PLATFORM_BIN_PATH
+       string "Path to toolchain binaries"
+       default "$PLATFORM_PREFIX/bin"
+
+config PLATFORM_LIB_PATH
+       string "Path to toolchain libraries"
+       default "$PLATFORM_PREFIX/include"
+
+config PLATFORM_INCLUDE_PATH
+       string "Path to toolchain include files"
+       default "$PLATFORM_PREFIX/include"
+
+endmenu
+
diff --git a/src/target/Kconfig.model b/src/target/Kconfig.model
new file mode 100644 (file)
index 0000000..a3a9745
--- /dev/null
@@ -0,0 +1,9 @@
+# Model selection (includes with a separate setup for each brand)
+
+source "src/target/Kconfig.posix"
+source "src/target/Kconfig.grandstream"
+source "src/target/Kconfig.gigaset"
+#TODO# source "src/target/Kconfig.fritzbox"
+#TODO# source "src/target/Kconfig.sipura"
+source "src/target/Kconfig.smc"
+
diff --git a/src/target/Kconfig.platform b/src/target/Kconfig.platform
new file mode 100644 (file)
index 0000000..9b125cc
--- /dev/null
@@ -0,0 +1,21 @@
+# Platform-specific settings (platforms are usually a SoC or CPU type)
+
+choice
+       prompt "3. Hardware platform (SoC/CPU/DSP class)"
+
+config PLATFORM_LOCAL
+       bool "Local POSIX system"
+       depends on TARGET_POSIX
+       default y
+
+config PLATFORM_TIC54x
+       bool "tic54x"
+       depends on TARGET_GRANDSTREAM_BT10x
+       default y
+
+config PLATFORM_TIC55x
+       bool "tic55x"
+       depends on TARGET_GRANDSTREAM_BT20x || TARGET_GRANDSTREAM_GXP20xx
+       default y
+
+endchoice
diff --git a/src/target/Kconfig.posix b/src/target/Kconfig.posix
new file mode 100644 (file)
index 0000000..ae7d1cd
--- /dev/null
@@ -0,0 +1,41 @@
+# POSIX-based target platforms
+
+choice
+       prompt "2. POSIX-based phone targets"
+       depends on TARGET_POSIX
+       default TARGET_LINUX_RAWSOCK
+
+config TARGET_LINUX_RAWSOCK
+       bool "Linux desktop"
+       depends on UNIMPLEMENTED
+       select TARGET_POSIX_RAWSOCK
+       help
+         This is a platform intended to run on the same platform as
+         used for building.  It is built on a raw socket, so it does
+         not require IPv6 support in the kernel.  It will obtain its
+         own network leases, so it should be tested for non-interference
+         if any other software is run on the same platform.
+
+         Once built, run the command src/target/rawsock/firmly0cpm.bin
+         on your current platform.  It will configure itself automatically.
+
+         TODO: sound devices?  keyboard?  display?
+
+         TODO: Demo entry. Not implemented yet.
+
+config TARGET_LINUX_TUNTEST
+       bool "Linux tunnel device"
+       depends on DEVEL
+       help
+         Test and demonstration target intended for development.
+
+         This creates a tunnel interface behind which the firmly.0cpm
+         firmware is working.  You can route/bridge/filter/simulate
+         the surrounding network in any way you like.
+
+         Once built, run the command src/target/tuntest/firmly0cpm.bin
+         on your current platform.  It will configure itself automatically.
+
+         TODO: sound devices?  keyboard?  display?
+
+endchoice
diff --git a/src/target/Kconfig.smc b/src/target/Kconfig.smc
new file mode 100644 (file)
index 0000000..765046f
--- /dev/null
@@ -0,0 +1,35 @@
+# SMC phone models -- quite a variety because they sell prototypes as products
+
+choice
+       prompt "2. SMC phone models"
+       depends on TARGET_SMC
+       default TARGET_SMC_DSP20x
+
+config TARGET_SMC_DSP20x
+       bool "SMC DSP200"
+       select PLATFORM_CM5000LF
+       help
+         The SMC DSP200 and DSP205 models are actually prototypes from
+         CrystalMedia, the fabless producer of the CM5000LF SoC in
+         these phones.  Strange as that may sound, the phones are
+         actually more powerful than quite a few others.
+
+         The firmware in the phones is notoriously hard to configure.
+         But it does include testing code, which allows for a lot of
+         control.  The 4-line serial interface runs at 57600 8N1 and
+         the pins are [3V3], TxD, RxD, GND.
+
+         After building the firmware image, it can be uploaded over
+         this serial link.  First, select ic.img by pressing Enter
+         over the link in the first 3 seconds after testing RAM.
+         Then use the Download User Program option.
+
+         Future versions of this firmware are probably going to
+         look as firmware updates: a gzipped fcodec.out, gzipped
+         ic.img and gzipped user program named voip.img, all
+         attached.  Finally, a CRC-32 checksum over all those,
+         appended as 8 uppercase hex characters.  Interestingly,
+         the GPL may require the rest to be recoded for that to
+         be distributable.
+
+endchoice
index 297b3db..2c34970 100644 (file)
@@ -2,8 +2,24 @@
 # Sort each target's object files into objs-bottom-y or objs-bottom-n:
 #
 
-objs-bottom-$(CONFIG_TARGET_LINUX_TUNTEST) += src/driver/util/linuxtuntest.o
+objs-bottom-$(CONFIG_TARGET_LINUX_TUNTEST) += src/driver/util/linuxtuntest.o src/driver/util/ledsimu.o
 
 metavars-$(CONFIG_TARGET_LINUX_TUNTEST) += HAVE_NET_LEADER=4
 
-includes-$(CONFIG_TARGET_LINUX_TUNTEST) += src/driver/util/linuxtuntest.h
+includes-$(CONFIG_TARGET_LINUX_TUNTEST) += bottom/linuxtuntest.h
+
+#
+# Platform-dependent specifics
+#
+ifdef CONFIG_PLATFORM_LOCAL
+include src/target/Makefile.local
+endif
+
+ifdef CONFIG_PLATFORM_TIC54x
+include src/target/Makefile.tic54x
+endif
+
+ifdef CONFIG_PLATFORM_TIC55x
+include src/target/Makefile.tic55x
+endif
+
index ce3d01e..b4ffcc5 100644 (file)
@@ -6,59 +6,61 @@
 
 
 /* The maximum number of supported handset */
-#define HAS_HANDSETS 1
+#define HAVE_HANDSETS 1
 
 /* Keyboard settings */
 #undef DETECTS_DTMF
-#define HAS_KBD_STARHASH       1
-#define HAS_KBD_ABCD           0
-#define HAS_KBD_FLASH          0
-#define HAS_KBD_LINES          6
-#define HAS_KBD_SOFT_FUNCTION  4
-#ifndef HAS_KBD_SIDECARS
-#   define HAS_KBD_SIDECARS    0
+#define HAVE_KBD_STARHASH      1
+#define HAVE_KBD_ABCD          0
+#define HAVE_KBD_FLASH         0
+#define HAVE_KBD_LINES         6
+#define HAVE_KBD_SOFT_FUNCTION 4
+#ifndef HAVE_KBD_SIDECARS
+#   define HAVE_KBD_SIDECARS   0
 #endif
-#define HAS_KBD_GENERIC                ((HAS_KBD_SIDECARS)*32)
-#define HAS_KBD_VOICEMAIL      1
-#define HAS_KBD_MENU           1
-#define HAS_KBD_UPDOWN         1
-#define HAS_KBD_LEFTRIGHT      1
-#define HAS_KBD_MUTE           1
-#define HAS_KBD_CONFERENCE     0
-#define HAS_KBD_HOLD           1
-#define HAS_KBD_TRANSFER       0
-#define HAS_KBD_PHONEBOOK      0
-#define HAS_KBD_VOLUPDOWN      1
-#define HAS_KBD_HEADSET                1
-#define HAS_KBD_SPEAKER                1
-#define HAS_KBD_HEADSET                1
-#define HAS_KBD_MISSEDCALLS    0
-#define HAS_KBD_REDIAL         0
+#define HAVE_KBD_GENERIC               ((HAVE_KBD_SIDECARS)*32)
+#define HAVE_KBD_VOICEMAIL     1
+#define HAVE_KBD_MENU          1
+#define HAVE_KBD_OK            0
+#define HAVE_KBD_ENTER         0
+#define HAVE_KBD_UPDOWN                1
+#define HAVE_KBD_LEFTRIGHT     1
+#define HAVE_KBD_MUTE          1
+#define HAVE_KBD_CONFERENCE    0
+#define HAVE_KBD_HOLD          1
+#define HAVE_KBD_TRANSFER      0
+#define HAVE_KBD_PHONEBOOK     0
+#define HAVE_KBD_VOLUPDOWN     1
+#define HAVE_KBD_HEADSET               1
+#define HAVE_KBD_SPEAKER               1
+#define HAVE_KBD_HANDSET               1
+#define HAVE_KBD_MISSEDCALLS   0
+#define HAVE_KBD_REDIAL                0
 
 /* Light settings */
-#define HAS_LED_MESSAGE                1
-#define HAS_LED_LINEKEYS       1
-#define HAS_LED_GENERIC                1
-#define HAS_LED_MUTE           1
-#define HAS_LED_HANDSET                1
-#define HAS_LED_HEADSET                1
-#define HAS_LED_SPEAKERPHONE   1
-#define HAS_LED_BACKLIGHT      1
+#define HAVE_LED_MESSAGE               1
+#define HAVE_LED_LINEKEYS      1
+#define HAVE_LED_GENERIC               1
+#define HAVE_LED_MUTE          1
+#define HAVE_LED_HANDSET               1
+#define HAVE_LED_HEADSET               1
+#define HAVE_LED_SPEAKERPHONE  1
+#define HAVE_LED_BACKLIGHT     1
 
 /* Display settings */
 
 /* Sound settings */
-#define HAS_HANDSET            1
-#define HAS_HEADSET            1
-#define HAS_SPEAKER_MIKE       1
+#define HAVE_HANDSET           1
+#define HAVE_HEADSET           1
+#define HAVE_SPEAKER_MIKE      1
 
 /* Line settings */
 
 /* Account settings */
 
 /* Media settings */
-#define HAS_MEDIA_VOICE                1
-#define HAS_MEDIA_VIDEO                0
-#define HAS_MEDIA_URI          0
-#define HAS_MEDIA_IMAGE                1
+#define HAVE_MEDIA_VOICE               1
+#define HAVE_MEDIA_VIDEO               0
+#define HAVE_MEDIA_URI         0
+#define HAVE_MEDIA_IMAGE               1
 
diff --git a/src/target/smc_dsp20x.h b/src/target/smc_dsp20x.h
new file mode 100644 (file)
index 0000000..f26ed78
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * http://devel.0cpm.org/ -- Open source SIP telephony firmware.
+ *
+ * Device-specific includes for Linksys SPA962
+ */
+
+
+/* The maximum number of supported handset */
+#define HAVE_HANDSETS 1
+
+/* Keyboard settings */
+#undef DETECTS_DTMF
+#define HAVE_KBD_STARHASH      1
+#define HAVE_KBD_ABCD          0
+#define HAVE_KBD_FLASH         0
+#define HAVE_KBD_LINES         0
+#define HAVE_KBD_SOFT_FUNCTION 0
+#define HAVE_KBD_GENERIC       0
+#define HAVE_KBD_VOICEMAIL     1
+#define HAVE_KBD_MENU          1
+#define HAVE_KBD_OK            0
+#define HAVE_KBD_ENTER         1
+#define HAVE_KBD_UPDOWN                1
+#define HAVE_KBD_LEFTRIGHT     1
+#define HAVE_KBD_MUTE          0
+#define HAVE_KBD_CONFERENCE    1
+#define HAVE_KBD_HOLD          1
+#define HAVE_KBD_TRANSFER      1
+#define HAVE_KBD_PHONEBOOK     0
+#define HAVE_KBD_VOLUPDOWN     1
+#define HAVE_KBD_HEADSET               0
+#define HAVE_KBD_SPEAKER               1
+#define HAVE_KBD_HANDSET               0
+#define HAVE_KBD_MISSEDCALLS   0
+#define HAVE_KBD_REDIAL                1
+
+/* Light settings */
+#define HAVE_LED_MESSAGE               1
+#define HAVE_LED_LINEKEYS      0
+#define HAVE_LED_GENERIC               0
+#define HAVE_LED_MUTE          0
+#define HAVE_LED_HANDSET               0
+#define HAVE_LED_HEADSET               0
+#define HAVE_LED_SPEAKERPHONE  0
+#define HAVE_LED_BACKLIGHT     1
+
+/* Display settings */
+
+/* Sound settings */
+#define HAVE_HANDSET           1
+#define HAVE_HEADSET           0
+#define HAVE_SPEAKER_MIKE      1
+
+/* Line settings */
+
+/* Account settings */
+
+/* Media settings */
+#define HAVE_MEDIA_VOICE               1
+#define HAVE_MEDIA_VIDEO               0
+#define HAVE_MEDIA_URI         0
+#define HAVE_MEDIA_IMAGE               0
+
+