The first version that was demonstrated to get an IPv6 address
authorRick van Rein <vanrein@hwdev.(none)>
Sat, 25 Jun 2011 10:33:06 +0000 (10:33 +0000)
committerRick van Rein <vanrein@hwdev.(none)>
Sat, 25 Jun 2011 10:33:06 +0000 (10:33 +0000)
on various networks, and (hackfully) show it on the display of
(only) a Grandstream BT200.  Autoboot first tries IPv6 autoconf
then DHCPv6, then falls back to a 6bed4 tunnel.  The first two
options worked on an IPv6-supporting LAN, the latter on a
retro network (aka IPv4-only).

80 files changed:
Makefile
TODO
bin/i2cp/i2cp.c
doc/coding.rst [new file with mode: 0644]
doc/porting.rst
doc/top2bottom.rst
include/0cpm/app.h
include/0cpm/cons.h
include/0cpm/cpu.h
include/0cpm/defaults.h
include/0cpm/event.h
include/0cpm/flash.h [new file with mode: 0644]
include/0cpm/irq.h
include/0cpm/kbd.h
include/0cpm/led.h
include/0cpm/netcmd.h
include/0cpm/netdb.h
include/0cpm/netfun.h
include/0cpm/netinet.h [new file with mode: 0644]
include/0cpm/resource.h
include/0cpm/show.h
include/0cpm/snd.h [new file with mode: 0644]
include/0cpm/timer.h
include/bottom/blackfin.h [new file with mode: 0644]
include/bottom/devel.h [new file with mode: 0644]
include/bottom/grandstream.h
include/bottom/ht162x.h
include/bottom/ksz8842.h
include/bottom/linuxtuntest.h
include/bottom/tic55x.h
include/stdbool.h
src/driver/Makefile
src/driver/ata/si3210.c
src/driver/ht162x.c
src/driver/ksz8842.c
src/driver/net/rtl8019as.c
src/driver/soc/tic54x.c
src/driver/soc/visba3.c
src/driver/tic55x/LICENSE-WARNING.TXT
src/driver/tic55x/dma.c [new file with mode: 0644]
src/driver/tic55x/gpio.c
src/driver/tic55x/grandstream-bt20x.c
src/driver/tic55x/int.c
src/driver/tic55x/isrmap.asm
src/driver/tic55x/timer.c
src/driver/tlv320aic2x.c
src/driver/util/ledsimu.c
src/driver/util/linuxtuntest.c
src/function/Kconfig
src/function/Kconfig.devel
src/function/Makefile
src/function/bootloader.c [new file with mode: 0644]
src/function/bootloader/main.c
src/function/develtest/echo.c
src/function/develtest/keys2display.c
src/function/develtest/netconsole.c
src/function/develtest/switch2led.c
src/function/develtest/timer2led.c
src/function/netconsole.c
src/function/sip6phone/topmain.c
src/kernel/app.c
src/kernel/cpu.c
src/kernel/led.c
src/kernel/net.c
src/kernel/resource.c
src/kernel/timer.c
src/net/6bed4.c [new file with mode: 0644]
src/net/Makefile
src/net/core.c
src/net/db.c
src/net/input.c
src/net/llconly.c [new file with mode: 0644]
src/net/reply.c
src/net/send.c
src/phone/app_zero.c
src/target/Kconfig.brand
src/target/Kconfig.platform
src/target/Makefile
src/target/linksys_spa962.h
src/target/smc_dsp20x.h

index 84f9edb..09eb50e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -94,14 +94,17 @@ tags: src/net/6bed4.c
 .PHONY += clean
 clean:
        rm -f $(objs-top-y) $(objs-top-n) $(objs-top-)
+       rm -f $(objs-top-kernel-y) $(objs-top-kernel-n) $(objs-top-kernel-)
+       rm -f $(objs-top-net-y) $(objs-top-net-n) $(objs-top-net-)
+       rm -f $(objs-top-phone-y) $(objs-top-phone-n) $(objs-top-phone-)
        # rm -f $(objs-top-net-y)
        # rm -f $(objs-top-phone-y)
-       rm -f $(objs-bottom-y)
+       rm -f $(objs-bottom-y) $(objs-bottom-n) $(objs-bottom-)
        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 $(objs-bottom-y:.o=.d) $(objs-bottom-n:.o=.d) $(objs-bottom-:.o=.d)
        rm -f bin/top-kernel.o bin/top-net.o bin/top-phone.o
        rm -f bin/top.o bin/bottom.o
        rm -f include/config.h
diff --git a/TODO b/TODO
index aac104d..efb9604 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,5 +1,5 @@
-TODO for firmly.0cpm
-====================
+TODO for 0cpm Firmerware
+========================
 
 The current code is a demonstration of a core principle, an alpha
 level implementation that does work.  It demonstrates a way of getting
@@ -31,7 +31,7 @@ look at:
   storage for servers for dns, ntp, sip-proxy.
 
 * tic55x's int.c driver: work out conditions for hibernation sleep.
+  In hibernation, also shutdown the codec.
 
-* tic55x's PLL: get better performance by increasing clock rate.  This
-  will influence other forms of timing, such as RAM, Network and Codec.
+* Append network stack with LLC1 (for TFTP) and LLC2 (for console).
 
index bd30dfd..e448b6e 100644 (file)
@@ -1,4 +1,22 @@
-/* i2cp.c -- EEPROM read/write over i2c */
+/* i2cp.c -- EEPROM read/write over i2c
+ *
+ * This file is provided as part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/doc/coding.rst b/doc/coding.rst
new file mode 100644 (file)
index 0000000..c5e8ae9
--- /dev/null
@@ -0,0 +1,125 @@
+-------------------------------------------
+Coding Practices for Firmerware Portability
+-------------------------------------------
+
+Writing code for embedded systems means having to deal with a variety of compilers,
+not all of the quality that we would like.  What follows is a set of coding rules
+that should keep you out of trouble.  Please follow them, even if your compiler
+does not reveal any problems -- the last thing you want your patch to do is to
+upset the code on another platform.
+
+
+.. contents::
+
+
+Code aesthetics
+===============
+
+Try not to mix styles, it makes code look ugly and inconsistent.
+
+* The coding style is a tabstop of 8 positions per indentation level.
+
+* All code blocks are enclosed in braces; the opening one behind the code
+  fragment introducing the block, and the closing one on a line on its own,
+  indented by the same amount as the line with the opening brace.
+
+* The bracket enclosing functional parameters is preceded with a space.
+
+
+Type mappings
+=============
+
+Not all architectures can access series of bytes as shorts or longwords.
+
+* Do not use ``htons()`` and ``ntohl()`` and so on.  These functions map a
+  packed representation of bits, assuming that these can be read from or
+  written to memory in that packed format.  This is not always true.  So
+  instead, use ``netset16()`` and ``netget32()`` and so on.  The types of
+  network-represented unsigned integers are ``nint8_t``, ``nint16_t`` and
+  ``nint32_t``.
+
+* Where possible, refrain from using variable-sized types, such as ``int``.
+  Instead, prefer ``uint16_t`` and such.  It is generally unsafe to assume
+  that the size of ``int`` is 32-bit; for instance, a DSP processor may
+  prefer 16-bit values.  Similarly, ``long long`` is not always 64-bit or
+  more.
+
+* Use ``uint16_t`` for internal representation, and ``nint16_t`` for the
+  representation of a 16-bit value in network buffers.
+
+* Do not rely on the ``<varargs.h>`` mechanism; sadly, it does not work on
+  all machines (probably due to variations in word sizes and memory models)
+  and the possibility of variable arguments in ``#define`` macros also is
+  not commonly implemented.
+
+
+Initialisation
+==============
+
+Setting values does not seem to work the same everywhere.
+
+* Initialise all global and stack variables before they are being used.
+  It is not generally safe to assume that they will be setup with zeroes.
+
+* Static variables may be set to a value at compile time, or assumed to
+  initialise at zero.
+
+* Static variables initialised inside a function body may on some compilers
+  be initialised for every invocation of the function, or entry of the
+  containing statement block.
+
+
+Declarations
+============
+
+Not all compilers are called ``gcc``, and some really show their age.
+
+* Within a statement block, do not write statements before the declarations
+  have all been made.  Modern compilers are forgiving in this respect, and
+  it is very tempting to use, but not all compilers are that modern.
+
+* The applications in a phone each have their own, fixed amount of storage.
+  This is allocated as global variables, taken from main memory.  They should
+  be declared static where module-local scope is possible.  There is very
+  little need for dynamicity; perhaps the network packet buffer is the
+  only exception.
+
+* Do not allocate large structures on stack; embedded environments do not
+  have a stack large enough to hold, say, a network packet buffer.
+
+
+Global names
+============
+
+If you declare global names in your modules, you naturally risk name clashes.
+
+* Global names starting with ``bottom_`` or ``top_`` are reserved for the API
+  between top and bottom halves of the code.  Do not use any such names
+  for other purposes.
+
+* Name clashes between top and bottom halves should be resolved by changing
+  the bottom-half name; the top is meant to co-operate with many kinds of
+  bottoms, and taking them all into account in global names would be highly
+  unpractical.
+
+* Never ever allow global names to be used accross the separation between
+  the top and bottom half.  If you need the API changed, contact us about
+  it instead of hacking a solution that will only work for you and frustrate
+  all the others.  You should be able to checkin any changes as separate
+  updates for top and bottom, in any order, assuming that the API is not
+  changed.
+
+
+Checking in code
+================
+
+* Not all toolchains are up-to-speed with dependencies.  Before assuming
+  code works, clean the entire target for a full rebuild and test.  We have
+  seen cases where changes in data structures led to incoherent interpretation
+  by modules, because they did not know their dependency on header files.
+
+* If your work changes both top and bottom halves, create separate patches
+  for them, and test them separately.  They should not change the API unless
+  this was first discussed and agreed; the design of the API should stay as
+  clean as possible.
+
index 1548728..f452e34 100644 (file)
@@ -388,11 +388,126 @@ Linux' ``i2c-parport`` interface as documented in the
 Vendor-specific
 ---------------
 
-Vendors sometimes develop their own connectors for development and
+Chip 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.
 
+Below is how I gained access to the initial phone demonstrating
+this project, the Grandstream BT200.  The chips driving these
+phones can be booted over I2C, and an interface to do just that
+is available externally.  All you need to do is hang EEPROMs on
+the I2C bus, and fill them with the necessary program from the
+computer (after passing it through a specially designed ``hex55``
+command).
+
+.. figure:: pix/bootfloppy-i2c-busside.jpg
+       :scale: 100
+       :alt: I2C bootfloppy, bus side
+
+       Since I2C is a bus, and multiple EEPROMs can be mounted
+       on it, the majority of the connections is the same on all
+       chips.  The ideal configuration therefore is a stack of
+       such chips.  Also nice and solid in handling when it
+       sits around on your desk.
+
+.. figure:: pix/bootfloppy-i2c-graycodedside.jpg
+       :scale: 100
+       :alt: I2C bootfloppy, gray-coded address selector side
+
+       The other side has 3 connectors A0/A1/A2 on the left;
+       these should each get a different address selector in
+       the form of different patterns of 1 and 0 bits.  Had
+       we used plain binary counting to enumerate the values,
+       then there would have been a lot of crossings.  Thanks
+       to `Gray coding`_ however, there are none.  It is actually
+       possible to draw a curly line between the pins that are
+       "1" and the ones that are "0" valued.  And to top it off
+       with even more nerdiness, all connections have been made
+       using pins that were either bent or clipped off at
+       another place.
+
+.. figure:: pix/bootfloppy-i2c-parport_pc.jpg
+       :scale: 100
+       :alt: I2C interface to development PC
+
+       The nice thing about I2C is that it is trivial to
+       connect to a Linux PC running the compiler and the
+       ``hex55`` utility that prepares code for the
+       bootloader built into the DSP chip.  In the kernel
+       documentation of ``i2c_parport`` there is a schema,
+       of which we picked the type 3 variant.  This involves
+       a few open-collector inverter chips taken from a
+       sinlge chip.  By bending the pins of such a chip
+       sideways, clipping them off and mounting the necessary
+       cross-connections and resistors on top, we managed to
+       fit the entire device in a standard DB-25 connector case.
+       (If something is so well hidden, you do want to
+       document the insides on a sticker, of course.)
+
+.. _`Gray coding` : http://en.wikipedia.org/wiki/Gray_code
+
+
+Making a flash backup
+=====================
+
+Assuming you can now boot the hardware with your own software, a
+good thing to aim for is to make a backup of the only vital bit
+of information in there -- the contents of the flash memory.  This
+can be done as soon as you manage to get the bootloader running,
+as one of the targets defined below.
+
+If the busses are a confusing mixture of 8-, 16- and 32-bit technology,
+you may want to be really sure you got it all.  You should be able
+to download the flash contents as a file the size of the contents of
+the flash memory chip; it should not contain any duplications.
+
+A nice way to test for duplications is to copy pages or other ranges
+from a TFTP-over-LLC1 download with ``dd`` and to compare them.  A
+good way of finding suggestions about such ranges can come from a
+bit of commandline handywork, like this::
+
+  hd ALLFLASH.BIN | sed 's/^[^ ]* //' | sort | uniq -c
+
+The lines shown will be prefixed by how often the shown combination
+of 16 bytes occurs in the firmware, at a 16-byte rounded address.
+If these are multiples of 2, or a power of 2, you can be fairly
+certain your downloading algorithm fails in a way that clones parts
+of the memory.  Also be sure to inspect the hexdump visually; signs
+of error are the occurrence of zeroes or ``ff`` values in all rows
+for a certain column.
+
+To give an indication, we initially found 32 copies of most of the
+data; after fixing a big this still was 2; after re-arranging the
+addressing scheme we ended up with only 310 copied lines in the
+hexdump passed through sort and uniq; out of a total of 37249.
+Clearly, the duplications left can be attributed to accidental
+collisions such as repeated strings or procedures.
+Once such a decently-looking copy of the entire flash has been
+downloaded, save it in a safe place, to ensure a way of future
+recovery.
+
+The safest approach to all this is to first write the bottom routine
+``bottom_flash_read()`` that reads the flash memory; once that shows
+no sign of misfunctioning, continue to write ``bottom_flash_write()``
+and work on it until a written image shows up correctly in the output
+of ``bottom_flash_read()``.  Send in arbitrary data, and check its
+arrival, (also) accross a power cycle.  Upload the original content
+and check that it is there.
+
+Find out the partitioning scheme of the flash memory, if any.  It
+is quite common to have parts that can be downloaded into the phone
+separately, for instance a bootloader, SIP firmware and ringtones.
+You want to know where each is located, and enter the table
+``bottom_flash_partition_table`` with the block ranges for each of
+the partitions.  It is common to end the table with an entry named
+``ALLFLASH.BIN`` covering the entire flash memory range.
+
+With full control over bootstrapping code (bypassing flash) and with
+a backup of the flash memory, you will never be caught with your
+trousers down -- you can always recover the flash to restore the
+original way of functioning for the device.
+
 
 
 Mapping your hardware
index 8b30fbc..25ae590 100644 (file)
@@ -4,8 +4,12 @@ TODO: TIME_MSEC, TIME_SEC, TIME_MIN, TIME_HOUR, TIME_DAY
 TODO: TIME_BEFORE(a,b)
 TODO: bottom_show_xxx() series of calls
 TODO: bottom_xxx_scan() and top_xxx() from develtests
-TODO: network_can_xxx() will be called before 1500 bytes free but then certainly called again before done
+TODO: top_network_can_xxx() will be called before 1500 bytes free but then certainly called again before done
 TODO: bottom_network_send/_recv() accept 32-bit transfers
+TODO: bottom_flash_read()/_write() to interact with flash memory partitions sequentially
+TODO: bottom_flash_partition_table [0:HAVE_FLASH_PARTITION_TABLE>
+TODO: bottom_flash_get_mac (uint8_t mac [6]) sets the MAC address at the buffer address
+TODO: top_timer_expiration MUST call bottom_time and bottom_timer_set (or return new timer expiration value)
 
 ----------------------------------------------
 Kernel API between Phone Bottom and Top Halves
@@ -720,6 +724,7 @@ the screen may be reserved for softbuttons and/or line buttons.
 Sound
 -----
 
+**Channels.**
 A phone can have a number of sound channels, and the configuration
 of the platform defines which are available.  The possible channels
 are:
@@ -739,10 +744,17 @@ The top half can make the following downcall to instruct the bottom
 half about the current sound channel to use.  This implies dropping
 any channel currently in use::
 
-       bottom_soundchannel (SOUND_NONE);
-       bottom_soundchannel (SOUND_HANDSET);
-       bottom_soundchannel (SOUND_SPEAKER);
-       bottom_soundchannel (SOUND_HEADSET);
+       void bottom_soundchannel_device (uint8_t chan, sounddev_t dev);
+       bottom_soundchannel_device (0, SOUNDDEV_NONE);
+       bottom_soundchannel_device (0, SOUNDDEV_HANDSET);
+       bottom_soundchannel_device (0, SOUNDDEV_SPEAKER);
+       bottom_soundchannel_device (0, SOUNDDEV_HEADSET);
+
+The first argument represents the sound channel index.  It is
+currently assumed that one such channel exists, but future versions
+of the software may support multiple, if the hardware can handle
+it.  This is the case with some codec chips used in phones, and
+may well pave the way for additional functions for the hardware.
 
 Naturally, the bottom half will never be asked to support a sound
 channel that it has not made available in the phone's configuration.
@@ -750,6 +762,172 @@ channel that it has not made available in the phone's configuration.
 Note that handling any buttons for speakerphone access and such are
 usually done by the top half.
 
+**Volume.**
+Every sound channel has its own volume setting.  This value may
+vary depending on the current use of the channel; if it plays a
+ringtone it may be set to a higher volume than during a call.
+These settings are made by the top half, and incremented by one
+at a time.  The setting 0 represents a muted channel, any higher
+value can be suggested by the top half to the bottom half.  If
+the suggestion is too high, the top half will reduce it to the
+maximum setting for the channel.  The top half must not keep
+its own idea of the volume, but instead read it from the sound
+channel.  Only when switching the nature of the traffic on the
+sound channel could it be retrieved and stored literally::
+
+       void bottom_soundchannel_setvolume (uint8_t chan, uint8_t vol);
+       uint8_t bottom_soundchannel_getvolume (uint8_t chan);
+
+As before, the channel code is currently always set to 0, and
+it may develop to more possible values in some later version.
+
+The function ``bottom_soundchannel_setvolume`` will not only
+detect and correct increments beyond the maximum value, it will
+also detect and correct wrap-around in an attempt to go below
+the zero volume, or mute.
+
+**Sample rate.**
+The bottom half is responsible for playback at as accurate a rate
+as possible.  Usually, this will mean using DMA to send samples
+out at a predetermined rate, which derives from an accurate crystal
+clock and may pass through PLLs and dividers before yielding the
+desired frequency.
+
+The frequencies to use are usually pretty standard; for example,
+8 kHz for many G.7xx codecs, and 16 kHz or 32 kHz for the ones
+with higher quality.  These are important to support accurately,
+as deviations might be audible and disrupt normal phone operation.
+
+For higher-end uses, such as playback of MP3, Vorbis or AAC, there
+may be a need for other sample rates.  It is probable that 48 kHz
+works without problems, but 44.1 kHz (the CD sample rate) is
+almost always going to be a problem -- the frequency is composed
+of numerous prime factors,
+44100=2\ :sup:`2`\ .3\ :sup:`2`\ .5\ :sup:`2`\ .7\ :sup:`2`\ --
+what a cruel joke, as it usually very hard to get all these
+factors into the operating frequency of a general purpose device,
+and so there is going to be some delay from time to time.
+
+The best approach is probably to set a slightly lower frequency
+and use counters to detect when a single sample should be
+tossed out of the mix.  If 44000 Hz is achievable, this would
+mean that 1 out of every 441 samples would have to be dropped.
+The opposite, namely the duplication of a sample needed as a
+result of a sample rate that is too high, may be easier where
+the sample-handling hardware supports it.  The choice can be
+made in an optimal way for the hardware used, as it is all
+concealed in the bottom layer which is aware of the hardware
+involved.
+
+The result is that every possible sample rate may be set, but
+that choosing common ones is still a good idea.  The calls to
+set the sample rate for playback or recording of sound are::
+
+       void bottom_codec_play_samplerate   (uint8_t chan, uint32_t samplerate);
+       void bottom_codec_record_samplerate (uint8_t chan, uint32_t samplerate);
+
+It is not safe in general to assume that playing and recording
+can be done at different sample rates, so always call both
+these functions with the same values -- we just want to
+keep the option open to separate the sample rates on platforms
+that support, perhaps in a future version of the firmware.
+
+The list of codecs that are offered from bottom to top half
+suggests samplerates that are known to work well for those
+codecs.
+
+**Codec play/record.**
+For the actual exchange of sound, a mapping from codec format to
+the internal format used for playback (usually 16-bit samples)
+is required.  This is the work of the codec, which principally is
+part of the bottom half because that enables the use of (existing)
+assembly code for the target processor, and possibly even support
+in hardware.
+
+The internal sound buffer has a concealed size, and top and bottom
+exchange how many samples they would like to put in there.  When
+a given amount of space is available (usually for a particular
+time period), the bottom will inform the top that it can map a
+certain number of samples into the bottom buffer.  This may or
+may not cover a complete network packet.  Upon completion, the
+notified routine returns a suggestion about the number of
+additional samples it suggests for next time.  If the bottom
+does not find the required samples in time, it will try to insert
+sensible samples, effectively delaying the delivery of sound.
+To handle noticeable network dropouts, the top can register
+non-delivery of sound packets with a special function.
+
+::
+
+       uint16_t top_codec_can_play   (uint8_t chan, uint16_t samples);
+       uint16_t top_codec_can_record (uint8_t chan, uint16_t samples);
+
+These functions indicate to the top half that sound packets may
+now be played or recorded, as soon as they are available.  The
+return value suggests the number of samples to allow on the
+next call, but the bottom is not required to follow that
+suggestion.  As a result, the top must always be willing to
+deliver parts of packets.  It does not need to combine packets,
+as it can return the length of a sequel packet as a suggested
+size for next time.
+
+::
+       int16_t bottom_codec_play   (uint8_t chan,
+                                    codec_t codec,
+                                    uint8_t *coded_samples, 
+                                    uint16_t coded_bytes,
+                                    uint16_t samples);
+
+       int16_t bottom_codec_record (uint8_t chan,
+                                    codec_t codec,
+                                    uint8_t *coded_samples,
+                                    uint16_t coded_bytes,
+                                    uint16_t samples);
+
+TODO: Why repeat ``codec`` for every piece of data?  It could
+change between packets, but not according to SIP?  Plus, it will
+probably not work on drivers that have lagging-behind effects
+such as DMA currently going on and being setup for later.
+
+These functions request the bottom half to employ a codec for
+mapping encoded bytes (with a given start pointer and maximum
+length) to the given number of samples.  The ``codec`` is a
+code that defines the mapping; the architecture defines a
+mapping from codec names to ``codec_t`` values.  When used as
+an argument to ``bottom_codec_record``, the encoding side of the
+codec will be used; in ``bottom_codec_play``, the codec will be
+used for decoding.
+
+The return value of these functions is as complex as the possible
+outcomes of these functions:
+
+* return value 0 means that ``coded_bytes`` have been consumed to
+  generate precisely ``samples`` samples.
+* return values <0 mean that ``coded_bytes`` are all used but
+  there are still samples missing; the return value indicates how
+  much to subtract from ``samples`` to get the achieved result.
+  Note that it is assumed that all ``coded_bytes`` are used up
+  at this point.  If that means keeping internal state in the
+  bottom half, then so be it.  (But this is not likely to occur,
+  because it would dramatically complicate packet loss handling.)
+* return values >>0 mean that all ``samples`` samples were
+  generated, but there are still the returned number of bytes
+  left from ``codec_bytes``.
+
+::
+       void bottom_codec_play_skip (codec_t codec, uint16_t samples);
+
+This instructs the playing half of the codec to skip the given
+number of samples on playback.  This is required when network
+traffic has gone missing.  If this function is not called to
+indicate having detected such out-of-order delivery, the bottom
+half would assume that the network path has incurred a new delay,
+for which it would insert extra samples to fill up and cause the
+phone to playback with the added delay.  The bottom half must be
+clever enough to handle accidental skipping until samples are
+played in the future.  A small delay before a packet is actually
+played may be healthy to avoid future sound glitches.
+
 
 Special hardware
 ================
index 38231f2..bfaf2e8 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Resource contention handlers.
  *
- * Resource contention handlers.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index 46a2aec..7c4173f 100644 (file)
@@ -1,10 +1,28 @@
 /* Console logging facility
  *
- * This implements logging over an LLC console, where supported.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This implements logging over an LLC console, where supported.
  * Messages are written to the log when sent as bottom_printf (fmt, ...)
  * This is passed to the console routines through inline functions, as
  * not all embedded compilers support varargs in #defines.  The functions
- * should reduce to no code without CONFIG_FUNCTION_DEVEL_NETCONSOLE.
+ * should reduce to no code without CONFIG_FUNCTION_NETCONSOLE.
  *
  * The formats are very close to those of printf():
  *  - %s %c %d %x print string or (NULL), char, decimal and hexadecimal
@@ -19,7 +37,7 @@
 #ifndef HEADER_CONSOLE
 #define HEADER_CONSOLE
 
-#ifndef CONFIG_FUNCTION_DEVEL_NETCONSOLE
+#ifndef CONFIG_FUNCTION_NETCONSOLE
        inline void bottom_printf (char *fmt, ...) { ; }
 #else
        void bottom_console_vprintf (char *fmt, va_list argh);
@@ -33,4 +51,4 @@
        }
 #endif
 
-#endif
+#endif /* CONFIG_FUNCTION_NETCONSOLE */
index 1666b35..a0afffe 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* CPU scheduling
  *
- * CPU scheduling
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index ec70433..0984fb3 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source SIP telephony firmware.
+/* Device-generic default settings for undefined phone variables.
  *
- * Device-generic default settings for undefined phone variables.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index 2253178..39dd421 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Event handling
  *
- * Event handling
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
diff --git a/include/0cpm/flash.h b/include/0cpm/flash.h
new file mode 100644 (file)
index 0000000..d98265f
--- /dev/null
@@ -0,0 +1,99 @@
+/* flash.h -- Interface to flash memory.
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This module enables reading and/or writing flash memory.
+ * It also details where the flash partition table is.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#ifndef HEADER_FLASH
+#define HEADER_FLASH
+
+#ifdef HAVE_FLASH_PARTITIONS
+
+/* The structure of a flash partition in the partition table.
+ * Definitions for the flags field follow.
+ *
+ * Bootable partitions will usually be checksummed to avoid that
+ * they take down the system; if a checksum fails, the booting
+ * does not take place and the partition will be skipped.  This
+ * provides a fallback mechanism for half-installed images.  If
+ * checksums are applied, they are local to the bottom half.
+ *
+ * A partition can be write-protected in general, or it may only
+ * be writeable if the entire image is first downloaded into RAM.
+ * A good example of the latter is the very first piece of booting
+ * codes; it is dangerous to replace, and this should only be done
+ * atomically, that is, not dependent on anything but sustained
+ * power supply; network protocols should definately not cause a
+ * problem.  This is why the _WRITE_AFTER_LOAD2RAM exists.  This
+ * particular condition will usually be met only in the dedicated
+ * bootloader image; and it may not be physically possible for all
+ * images but the smallest.  The bootloader is definately designed
+ * to be one such small image, so it will always be setup safely.
+ */
+struct flashpart {
+       uint16_t flags;
+       uint8_t *filename;
+       uint16_t firstblock;
+       uint16_t numblocks;
+};
+
+#define FLASHPART_FLAG_BOOTABLE                        0x0001
+#define FLASHPART_FLAG_CHECKSUMMED             0x0002
+
+#define FLASHPART_FLAG_WRITEPROTECT            0x0010
+#define FLASHPART_FLAG_WRITE_AFTER_LOAD2RAM    0x0020
+
+#define FLASHPART_FLAG_LAST                    0x8000
+
+
+/* An external definition (usually in phone-specific code)
+ * contains an array of one or more entries of flashpart
+ * structures.  Only the last will have the FLASHPART_FLAG_LAST
+ * flag set.
+ *
+ * There will usually be one partition with name "ALLFLASH.BIN"
+ * that covers the entire flash memory, including things that
+ * may not actually be in any partition.  Usually, this is the
+ * last entry in the flash partition table.
+ */
+extern struct flashpart bottom_flash_partition_table [];
+
+
+/* Read a 512-byte block from flash.
+ * The return value indicates success.
+ */
+bool bottom_flash_read (uint16_t blocknr, uint8_t data [512]);
+
+
+/* Write a 512-byte block to flash.  It is assumed that this
+ * is done sequentially; any special treatment for a header
+ * page will be done by the bottom layer, not the top.
+ * The return value indicates success.
+ */
+bool bottom_flash_write (uint16_t blocknr, uint8_t data [512]);
+
+
+#endif /* HAVE_FLASH_PARTITIONS */
+
+#endif /* HEADER_FLASH */
index 725573f..37b7538 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Interrupt drivers
  *
- * Interrupt drivers
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
@@ -35,7 +48,11 @@ struct irq_type {
 };
 
 
-/* Manage interrupts; fire one */
+/* Add an IRQ to the queue of interrupt tasks to be scheduled.
+ * This routine must always be called with interrupts inactive;
+ * either as part of an interrupt routine, or when called in the
+ * course of the main program, from within a critical region.
+ */
 void irq_fire (irq_t *irq);
 
 /* Top-half operations to manipulate interrupts */
index 83f193c..0a623c3 100644 (file)
@@ -1,10 +1,26 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Keyboard drivers
  *
- * Keyboard drivers
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
+#ifndef HEADER_KBD
+#define HEADER_KBD
+
 
 /* Button classes: DTMF, function-specific, lines, soft functions, userprog */
 typedef enum {
@@ -45,3 +61,5 @@ void top_button_press (buttonclass_t bcl, buttoncode_t cde);
 void top_button_release (void);
 void top_hook_update (bool offhook);
 
+
+#endif /* HEADER_KBD */
index fc85a7e..bf66139 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* LED drivers
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * LED drivers
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index a993265..3e02dea 100644 (file)
@@ -1,7 +1,24 @@
-/*
- * bpfcmd.h -- Berkeley Packet Filter (ish) command set.
+/* bpfcmd.h -- Berkeley Packet Filter (ish) command set.
  *
- * This defines a virtual machine which is based on the BPF
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This defines a virtual machine which is based on the BPF
  * machine, as that is very suitable for taking apart packets,
  * storing juicy parts on a scratchpad, and finally deciding
  * what to do with it.
index a2acb40..ed226f0 100644 (file)
@@ -1,6 +1,20 @@
 /* netdb.h -- Network database structures
  *
- * From: Rick van Rein <rick@openfortress.nl>
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
  * Some other protocols may use IPv4 for the time being: DNS, NTP.
  */
 
+typedef enum ip4peer ip4peer_t;
+enum ip4peer {
+       IP4_PEER_GATEWAY,
+       IP4_PEER_DNS0,
+       IP4_PEER_DNS1,
+       IP4_PEER_COUNT
+};
+
 struct ip4binding {
-       struct ip4binding *next;        // Linked-list -- TODO:ARRAY?
-       uint32_t ip4addr;               // My IPv4 address -- network order
-       uint32_t ip4mask;               // My IPv4 mask -- network order
-       uint32_t ip4gateway;            // My IPv4 gateway
-       uint32_t ip4timeout;            // The timeout for ip4addr / ip4gateway
-       uint32_t ip4dns [2];            // DNS servers available on this route
+       struct ip4binding *next;                // Linked-list -- TODO:ARRAY?
+       uint32_t ip4addr;                       // My IPv4 address -- network order
+       uint32_t ip4mask;                       // My IPv4 mask -- network order
+       uint32_t ip4timeout;                    // The timeout for ip4addr / ip4gateway
+       uint32_t ip4peer [IP4_PEER_COUNT];      // Gateway and DNS servers, some local
+       uint8_t ip4peermac [IP4_PEER_COUNT][6]; // MAC addresses of local IPv4 peers
        //TODO:NONE?// uint16_t flags;                  // See I4B_xxx below
 };
 
 
+
 /* IPv6 routing and addressing information.
  * 
  * This structure is used to find the routing information from a particular
@@ -43,6 +66,7 @@ struct ip4binding {
  * the route is of course set in stone.
  */
 struct ip6binding {
+       irqtimer_t timer;               // Timer to wait for tentative, expire
        struct ip6binding *next;        // Linked-list -- TODO:ARRAY?
        uint8_t ip6addr [16];           // My IPv6 address
        uint8_t ip6uplink [16];         // The router's link-local address
@@ -56,7 +80,7 @@ struct ip6binding {
 
 /* An ip6binding can be obtained from one of a few sources */
 #define I6B_ROUTE_SOURCE_MASK          0x00f0
-#define I6B_ROUTE_SOURCE_6BED4_FLAG    0x0080  /* Native if not 6bed4 */
+#define I6B_ROUTE_SOURCE_6BED4_MASK    0x0080  /* Native if not 6bed4 */
 #define I6B_ROUTE_SOURCE_AUTOCONF      0x0000  /* AUTO6 + NATIVE */
 #define I6B_ROUTE_SOURCE_DHCP          0x0010  /* DHCP6 + NATIVE */
 #define I6B_ROUTE_SOURCE_STATIC                0x0020  /* STAT6 + NATIVE */
@@ -70,6 +94,7 @@ struct ip6binding {
 /* An ip6binding can be in active use; expiry then only sets a flag */
 #define I6B_ACTIVE                     0x0200
 #define I6B_EXPIRED                    0x0400
+#define I6B_DEFEND_ME                  0x0800
 
 
 /* The netdb structure with the binding structures */
index e7aed8d..67f7f4a 100644 (file)
@@ -1,3 +1,23 @@
+/* Network function prototypes
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
 #ifndef HEADER_NETFUN
 #define HEADER_NETFUN
 
@@ -64,10 +84,10 @@ struct packet {
 uint16_t netcore_checksum_areas (void *area0, ...);
 void netcore_send_buffer (intptr_t *mem, uint8_t *wbuf);
 void netcore_bootstrap_initiate (void);
+void netcore_bootstrap_success (void);
+void netcore_bootstrap_restart (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);
@@ -89,6 +109,8 @@ uint8_t *netsend_icmp6_router_solicit (uint8_t *pout, intptr_t *mem);
 uint8_t *netsend_icmp6_ngb_sol (uint8_t *pout, intptr_t *mem);
 uint8_t *netsend_dhcp4_discover (uint8_t *pout, intptr_t *mem);
 uint8_t *netsend_dhcp6_solicit (uint8_t *pout, intptr_t *mem);
+uint8_t *netsend_udp6 (uint8_t *pout, intptr_t *mem);
+uint8_t *netsend_arp_query (uint8_t *pout, intptr_t *mem);
 
 void netdb_initialise (void);
 uint8_t *netdb_router_advertised (uint8_t *pout, intptr_t *mem);
@@ -97,6 +119,8 @@ uint8_t *netdb_dhcp4_ack (uint8_t *pout, intptr_t *mem);
 uint8_t *netdb_dhcp4_nak (uint8_t *pout, intptr_t *mem);
 uint8_t *netdb_dhcp6_reply (uint8_t *pout, intptr_t *mem);
 uint8_t *netdb_dhcp6_reconfigure (uint8_t *pout, intptr_t *mem);
+uint8_t *netdb_arp_reply (uint8_t *pkt, intptr_t *mem);
+void netdb_dhcp6_recurse_options (nint16_t *dhcp6opts, uint16_t optlen);
 
 uint8_t *netout (uint8_t *pkt, uint32_t pktlen, intptr_t *mem);
 
diff --git a/include/0cpm/netinet.h b/include/0cpm/netinet.h
new file mode 100644 (file)
index 0000000..210b472
--- /dev/null
@@ -0,0 +1,619 @@
+/* netinet.h -- network data structures
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* 0cpm firmerware
+ *
+ * Much of what follows was taken from Linux, but trimmed down to
+ * convey only uint8_t[] arrays to represent network packets.  The
+ * need for this arises from some DSP processors like tic55x, that
+ * work under an unconventional
+ *     sizeof (uint8_t) == sizeof (uint16_t) == 2
+ * because their memory is 16-bit and can be used as 8-bit-only.
+ *
+ * The only way to generically overlay packets with structs is to
+ * define all parts of those structs in terms of uint8_t[] and
+ * use generic routines netget16() / netput16() and so on to change
+ * the values stored in these fields.  Of course, optimisations are
+ * possible for concrete local architectures; this is why the defs
+ * of netget16, netput16 and so on are only done if the symbols have
+ * not been defined in the bottom-half specific include files.
+ */
+
+
+#ifndef HEADER_NETINET
+#define HEADER_NETINET
+
+
+/* The network-specific definitions of 8, 16 and 32 bit values that
+ * are generic enough to work on special DSP processors as well,
+ * together with their utility functions.  Use the netget16, netput16
+ * and so on instead of manipulating values with htons, ntohs and so on.
+ */
+
+typedef struct { uint8_t b0             } nint8_t;
+typedef struct { uint8_t b0, b1         } nint16_t;
+typedef struct { uint8_t b0, b1, b2, b3 } nint32_t;
+
+#ifndef netget8
+#define netget8(a) ((uint8_t) (a).b0)
+#endif
+
+#ifndef netget16
+#define netget16(a) ((((uint16_t) (a).b0) << 8) | ((uint16_t) ((a).b1)))
+#endif
+
+#ifndef netget32
+#define netget32(a) ((((uint32_t) (a).b0) << 24) | (((uint32_t) (a).b1) << 16) | (((uint32_t) (a).b2) << 8) | (((uint32_t) (a).b3)))
+#endif
+
+#ifndef netset8
+#define netset8(a,v) (((a).b0) = (v))
+#endif
+
+#ifndef netset16
+#define netset16(a,v) (((a).b0 = ((v) >> 8)), ((a).b1 = ((v) & 0xff)), (v))
+#endif
+
+#ifndef netset32
+#define netset32(a,v) (((a).b0 = ((v) >> 24)), ((a).b1 = (((v) >> 16) & 0xff)), ((a).b2 = (((v) >> 8) & 0xff)), ((a).b3 = ((v) & 0xff)), (v))
+#endif
+
+/* Note: In bottom-specific overrides, raise an error if these values
+ * are defined before they are redefined for that specific bottom.
+ * This will raise awareness of the order of header files, and avoid
+ * different definitions (albeit semantically compatible) in various
+ * files due to varying include orders.  The right order is always
+ * to include the bottom-half include files before the top half files.
+ */
+
+
+/* Start includes, mostly taken from Linux header files */
+
+
+/* Standard well-defined IP protocols.  */
+enum {
+  IPPROTO_IP = 0,               /* Dummy protocol for TCP               */
+  IPPROTO_ICMP = 1,             /* Internet Control Message Protocol    */
+  IPPROTO_IGMP = 2,             /* Internet Group Management Protocol   */
+  IPPROTO_IPIP = 4,             /* IPIP tunnels (older KA9Q tunnels use 94) */
+  IPPROTO_TCP = 6,              /* Transmission Control Protocol        */
+  IPPROTO_EGP = 8,              /* Exterior Gateway Protocol            */
+  IPPROTO_PUP = 12,             /* PUP protocol                         */
+  IPPROTO_UDP = 17,             /* User Datagram Protocol               */
+  IPPROTO_IDP = 22,             /* XNS IDP protocol                     */
+  IPPROTO_DCCP = 33,            /* Datagram Congestion Control Protocol */
+  IPPROTO_RSVP = 46,            /* RSVP protocol                        */
+  IPPROTO_GRE = 47,             /* Cisco GRE tunnels (rfc 1701,1702)    */
+
+  IPPROTO_IPV6   = 41,          /* IPv6-in-IPv4 tunnelling              */
+
+  IPPROTO_ESP = 50,            /* Encapsulation Security Payload protocol */
+  IPPROTO_AH = 51,             /* Authentication Header protocol       */
+  IPPROTO_BEETPH = 94,         /* IP option pseudo header for BEET */
+  IPPROTO_PIM    = 103,         /* Protocol Independent Multicast       */
+
+  IPPROTO_COMP   = 108,                /* Compression Header protocol */
+  IPPROTO_SCTP   = 132,         /* Stream Control Transport Protocol    */
+  IPPROTO_UDPLITE = 136,        /* UDP-Lite (RFC 3828)                  */
+
+  IPPROTO_RAW    = 255,         /* Raw IP packets                       */
+  IPPROTO_MAX
+};
+
+/*
+ *      IPV6 extension headers
+ */
+#define IPPROTO_HOPOPTS         0       /* IPv6 hop-by-hop options      */
+#define IPPROTO_ROUTING         43      /* IPv6 routing header          */
+#define IPPROTO_FRAGMENT        44      /* IPv6 fragmentation header    */
+#define IPPROTO_ICMPV6          58      /* ICMPv6                       */
+#define IPPROTO_NONE            59      /* IPv6 no next header          */
+#define IPPROTO_DSTOPTS         60      /* IPv6 destination options     */
+#define IPPROTO_MH              135     /* IPv6 mobility header         */
+
+/*
+ *      IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+ *      and FCS/CRC (frame check sequence). 
+ */
+
+#define ETH_ALEN        6               /* Octets in one ethernet addr   */
+#define ETH_HLEN        14              /* Total octets in header.       */
+#define ETH_ZLEN        60              /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN    1500            /* Max. octets in payload        */
+#define ETH_FRAME_LEN   1514            /* Max. octets in frame sans FCS */
+#define ETH_FCS_LEN     4               /* Octets in the FCS             */
+
+/* Ethernet protocol ID's */
+#define ETHERTYPE_PUP           0x0200          /* Xerox PUP */
+#define ETHERTYPE_SPRITE        0x0500          /* Sprite */
+#define ETHERTYPE_IP            0x0800          /* IP */
+#define ETHERTYPE_ARP           0x0806          /* Address resolution */
+#define ETHERTYPE_REVARP        0x8035          /* Reverse ARP */
+#define ETHERTYPE_AT            0x809B          /* AppleTalk protocol */
+#define ETHERTYPE_AARP          0x80F3          /* AppleTalk ARP */
+#define ETHERTYPE_VLAN          0x8100          /* IEEE 802.1Q VLAN tagging */
+#define ETHERTYPE_IPX           0x8137          /* IPX */
+#define ETHERTYPE_IPV6          0x86dd          /* IP protocol version 6 */
+#define ETHERTYPE_LOOPBACK      0x9000          /* used to test interfaces */
+
+
+#define ETHER_ADDR_LEN  ETH_ALEN                 /* size of ethernet addr */
+#define ETHER_TYPE_LEN  2                        /* bytes in type field */
+#define ETHER_CRC_LEN   4                        /* bytes in CRC field */
+#define ETHER_HDR_LEN   ETH_HLEN                 /* total octets in header */
+#define ETHER_MIN_LEN   (ETH_ZLEN + ETHER_CRC_LEN) /* min packet length */
+#define ETHER_MAX_LEN   (ETH_FRAME_LEN + ETHER_CRC_LEN) /* max packet length */
+
+
+/*
+ *      These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP      0x0060          /* Ethernet Loopback packet     */
+#define ETH_P_PUP       0x0200          /* Xerox PUP packet             */
+#define ETH_P_PUPAT     0x0201          /* Xerox PUP Addr Trans packet  */
+#define ETH_P_IP        0x0800          /* Internet Protocol packet     */
+#define ETH_P_X25       0x0805          /* CCITT X.25                   */
+#define ETH_P_ARP       0x0806          /* Address Resolution packet    */
+#define ETH_P_BPQ       0x08FF          /* G8BPQ AX.25 Ethernet Packet  [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_IEEEPUP   0x0a00          /* Xerox IEEE802.3 PUP packet */
+#define ETH_P_IEEEPUPAT 0x0a01          /* Xerox IEEE802.3 PUP Addr Trans packet */
+#define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
+#define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
+#define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
+#define ETH_P_DNA_RT    0x6003          /* DEC DNA Routing              */
+#define ETH_P_LAT       0x6004          /* DEC LAT                      */
+#define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
+#define ETH_P_CUST      0x6006          /* DEC Customer use             */
+#define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
+#define ETH_P_RARP      0x8035          /* Reverse Addr Res packet      */
+#define ETH_P_ATALK     0x809B          /* Appletalk DDP                */
+#define ETH_P_AARP      0x80F3          /* Appletalk AARP               */
+#define ETH_P_8021Q     0x8100          /* 802.1Q VLAN Extended Header  */
+#define ETH_P_IPX       0x8137          /* IPX over DIX                 */
+#define ETH_P_IPV6      0x86DD          /* IPv6 over bluebook           */
+#define ETH_P_PAUSE     0x8808          /* IEEE Pause frames. See 802.3 31B */
+#define ETH_P_SLOW      0x8809          /* Slow Protocol. See 802.3ad 43B */
+#define ETH_P_WCCP      0x883E          /* Web-cache coordination protocol
+                                         * defined in draft-wilson-wrec-wccp-v2-00.txt */
+#define ETH_P_PPP_DISC  0x8863          /* PPPoE discovery messages     */
+#define ETH_P_PPP_SES   0x8864          /* PPPoE session messages       */
+#define ETH_P_MPLS_UC   0x8847          /* MPLS Unicast traffic         */
+#define ETH_P_MPLS_MC   0x8848          /* MPLS Multicast traffic       */
+#define ETH_P_ATMMPOA   0x884c          /* MultiProtocol Over ATM       */
+#define ETH_P_ATMFATE   0x8884          /* Frame-based ATM Transport
+                                         * over Ethernet
+                                         */
+#define ETH_P_AOE       0x88A2          /* ATA over Ethernet            */
+#define ETH_P_TIPC      0x88CA          /* TIPC                         */
+
+/* Internet address.  */
+typedef nint32_t in_addr_t;
+struct in_addr
+  {
+    in_addr_t s_addr;
+  };
+
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+struct ip
+  {
+// #if __BYTE_ORDER == __LITTLE_ENDIAN
+    // unsigned int ip_hl:4;               /* header length */
+    // unsigned int ip_v:4;                /* version */
+// #endif
+// #if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned int ip_v:4;                /* version */
+    unsigned int ip_hl:4;               /* header length */
+// #endif
+    nint8_t ip_tos;                    /* type of service */
+    nint16_t ip_len;                     /* total length */
+    nint16_t ip_id;                      /* identification */
+    nint16_t ip_off;                     /* fragment offset field */
+#define IP_RF 0x8000                    /* reserved fragment flag */
+#define IP_DF 0x4000                    /* dont fragment flag */
+#define IP_MF 0x2000                    /* more fragments flag */
+#define IP_OFFMASK 0x1fff               /* mask for fragmenting bits */
+    nint8_t ip_ttl;                    /* time to live */
+    nint8_t ip_p;                      /* protocol */
+    nint16_t ip_sum;                     /* checksum */
+    struct in_addr ip_src, ip_dst;      /* source and dest address */
+  };
+
+
+struct iphdr
+  {
+    nint8_t version_ihl;
+    nint8_t tos;
+    nint16_t tot_len;
+    nint16_t id;
+    nint16_t frag_off;
+    nint8_t ttl;
+    nint8_t protocol;
+    nint16_t check;
+    nint32_t saddr;
+    nint32_t daddr;
+    /*The options start here. */
+  };
+
+
+
+struct icmp6_hdr
+  {
+    nint8_t     icmp6_type;   /* type field */
+    nint8_t     icmp6_code;   /* code field */
+    nint16_t    icmp6_cksum;  /* checksum field */
+    union
+      {
+        nint32_t  icmp6_un_data32[1]; /* type-specific field */
+        nint16_t  icmp6_un_data16[2]; /* type-specific field */
+        nint8_t   icmp6_un_data8[4];  /* type-specific field */
+      } icmp6_dataun;
+  };
+
+#define icmp6_data32    icmp6_dataun.icmp6_un_data32
+#define icmp6_data16    icmp6_dataun.icmp6_un_data16
+#define icmp6_data8     icmp6_dataun.icmp6_un_data8
+#define icmp6_pptr      icmp6_data32[0]  /* parameter prob */
+#define icmp6_mtu       icmp6_data32[0]  /* packet too big */
+#define icmp6_id        icmp6_data16[0]  /* echo request/reply */
+#define icmp6_seq       icmp6_data16[1]  /* echo request/reply */
+#define icmp6_maxdelay  icmp6_data16[0]  /* mcast group membership */
+
+
+#define ICMP6_DST_UNREACH             1
+#define ICMP6_PACKET_TOO_BIG          2
+#define ICMP6_TIME_EXCEEDED           3
+#define ICMP6_PARAM_PROB              4
+
+#define ICMP6_INFOMSG_MASK  0x80    /* all informational messages */
+
+#define ICMP6_ECHO_REQUEST          128
+#define ICMP6_ECHO_REPLY            129
+#define MLD_LISTENER_QUERY          130
+#define MLD_LISTENER_REPORT         131
+#define MLD_LISTENER_REDUCTION      132
+
+#define ICMP6_DST_UNREACH_NOROUTE     0 /* no route to destination */
+#define ICMP6_DST_UNREACH_ADMIN       1 /* communication with destination */
+                                        /* administratively prohibited */
+#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */
+#define ICMP6_DST_UNREACH_ADDR        3 /* address unreachable */
+#define ICMP6_DST_UNREACH_NOPORT      4 /* bad port */
+
+#define ICMP6_TIME_EXCEED_TRANSIT     0 /* Hop Limit == 0 in transit */
+#define ICMP6_TIME_EXCEED_REASSEMBLY  1 /* Reassembly time out */
+
+#define ICMP6_PARAMPROB_HEADER        0 /* erroneous header field */
+#define ICMP6_PARAMPROB_NEXTHEADER    1 /* unrecognized Next Header */
+#define ICMP6_PARAMPROB_OPTION        2 /* unrecognized IPv6 option */
+
+
+#define ND_ROUTER_SOLICIT           133
+#define ND_ROUTER_ADVERT            134
+#define ND_NEIGHBOR_SOLICIT         135
+#define ND_NEIGHBOR_ADVERT          136
+#define ND_REDIRECT                 137
+
+#define ND_OPT_SOURCE_LINKADDR          1
+#define ND_OPT_TARGET_LINKADDR          2
+#define ND_OPT_PREFIX_INFORMATION       3
+#define ND_OPT_REDIRECTED_HEADER        4
+#define ND_OPT_MTU                      5
+#define ND_OPT_RTR_ADV_INTERVAL         7
+#define ND_OPT_HOME_AGENT_INFO          8
+
+#define ND_OPT_PI_FLAG_ONLINK   0x80
+#define ND_OPT_PI_FLAG_AUTO     0x40
+#define ND_OPT_PI_FLAG_RADDR    0x20
+
+
+
+/*
+ * Internal of an ICMP Router Advertisement
+ */
+struct icmp_ra_addr
+{
+  nint32_t ira_addr;
+  nint32_t ira_preference;
+};
+
+
+struct icmp
+{
+  nint8_t  icmp_type;  /* type of message, see below */
+  nint8_t  icmp_code;  /* type sub code */
+  nint16_t icmp_cksum; /* ones complement checksum of struct */
+  union
+  {
+    nint8_t ih_pptr;             /* ICMP_PARAMPROB */
+    struct in_addr ih_gwaddr;   /* gateway address */
+    struct ih_idseq             /* echo datagram */
+    {
+      nint16_t icd_id;
+      nint16_t icd_seq;
+    } ih_idseq;
+    nint32_t ih_void;
+
+    /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
+    struct ih_pmtu
+    {
+      nint16_t ipm_void;
+      nint16_t ipm_nextmtu;
+    } ih_pmtu;
+
+    struct ih_rtradv
+    {
+      nint8_t irt_num_addrs;
+      nint8_t irt_wpa;
+      nint16_t irt_lifetime;
+    } ih_rtradv;
+  } icmp_hun;
+#define icmp_pptr       icmp_hun.ih_pptr
+#define icmp_gwaddr     icmp_hun.ih_gwaddr
+#define icmp_id         icmp_hun.ih_idseq.icd_id
+#define icmp_seq        icmp_hun.ih_idseq.icd_seq
+#define icmp_void       icmp_hun.ih_void
+#define icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
+#define icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
+#define icmp_num_addrs  icmp_hun.ih_rtradv.irt_num_addrs
+#define icmp_wpa        icmp_hun.ih_rtradv.irt_wpa
+#define icmp_lifetime   icmp_hun.ih_rtradv.irt_lifetime
+  union
+  {
+    struct
+    {
+      nint32_t its_otime;
+      nint32_t its_rtime;
+      nint32_t its_ttime;
+    } id_ts;
+    struct
+    {
+      struct ip idi_ip;
+      /* options and then 64 bits of data */
+    } id_ip;
+    struct icmp_ra_addr id_radv;
+    nint32_t   id_mask;
+    nint8_t    id_data[1];
+  } icmp_dun;
+#define icmp_otime      icmp_dun.id_ts.its_otime
+#define icmp_rtime      icmp_dun.id_ts.its_rtime
+#define icmp_ttime      icmp_dun.id_ts.its_ttime
+#define icmp_ip         icmp_dun.id_ip.idi_ip
+#define icmp_radv       icmp_dun.id_radv
+#define icmp_mask       icmp_dun.id_mask
+#define icmp_data       icmp_dun.id_data
+};
+
+
+struct icmphdr
+{
+  nint8_t type;                /* message type */
+  nint8_t code;                /* type sub-code */
+  nint16_t checksum;
+  union
+  {
+    struct
+    {
+      nint16_t id;
+      nint16_t sequence;
+    } echo;                     /* echo datagram */
+    nint32_t   gateway;        /* gateway address */
+    struct
+    {
+      nint16_t __unused;
+      nint16_t mtu;
+    } frag;                     /* path mtu discovery */
+  } un;
+};
+
+
+#define ICMP_ECHOREPLY          0       /* Echo Reply                   */
+#define ICMP_DEST_UNREACH       3       /* Destination Unreachable      */
+#define ICMP_SOURCE_QUENCH      4       /* Source Quench                */
+#define ICMP_REDIRECT           5       /* Redirect (change route)      */
+#define ICMP_ECHO               8       /* Echo Request                 */
+#define ICMP_TIME_EXCEEDED      11      /* Time Exceeded                */
+#define ICMP_PARAMETERPROB      12      /* Parameter Problem            */
+#define ICMP_TIMESTAMP          13      /* Timestamp Request            */
+#define ICMP_TIMESTAMPREPLY     14      /* Timestamp Reply              */
+#define ICMP_INFO_REQUEST       15      /* Information Request          */
+#define ICMP_INFO_REPLY         16      /* Information Reply            */
+#define ICMP_ADDRESS            17      /* Address Mask Request         */
+#define ICMP_ADDRESSREPLY       18      /* Address Mask Reply           */
+#define NR_ICMP_TYPES           18
+
+
+/* Codes for UNREACH. */
+#define ICMP_NET_UNREACH        0       /* Network Unreachable          */
+#define ICMP_HOST_UNREACH       1       /* Host Unreachable             */
+#define ICMP_PROT_UNREACH       2       /* Protocol Unreachable         */
+#define ICMP_PORT_UNREACH       3       /* Port Unreachable             */
+#define ICMP_FRAG_NEEDED        4       /* Fragmentation Needed/DF set  */
+#define ICMP_SR_FAILED          5       /* Source Route failed          */
+#define ICMP_NET_UNKNOWN        6
+#define ICMP_HOST_UNKNOWN       7
+#define ICMP_HOST_ISOLATED      8
+#define ICMP_NET_ANO            9
+#define ICMP_HOST_ANO           10
+#define ICMP_NET_UNR_TOS        11
+#define ICMP_HOST_UNR_TOS       12
+#define ICMP_PKT_FILTERED       13      /* Packet filtered */
+#define ICMP_PREC_VIOLATION     14      /* Precedence violation */
+#define ICMP_PREC_CUTOFF        15      /* Precedence cut off */
+#define NR_ICMP_UNREACH         15      /* instead of hardcoding immediate value */
+
+/* Codes for REDIRECT. */
+#define ICMP_REDIR_NET          0       /* Redirect Net                 */
+#define ICMP_REDIR_HOST         1       /* Redirect Host                */
+#define ICMP_REDIR_NETTOS       2       /* Redirect Net for TOS         */
+#define ICMP_REDIR_HOSTTOS      3       /* Redirect Host for TOS        */
+
+/* Codes for TIME_EXCEEDED. */
+#define ICMP_EXC_TTL            0       /* TTL count exceeded           */
+#define ICMP_EXC_FRAGTIME       1       /* Fragment Reass time exceeded */
+
+
+
+struct udphdr
+{
+  nint16_t source;
+  nint16_t dest;
+  nint16_t len;
+  nint16_t check;
+};
+
+
+/* IPv6 address */
+struct in6_addr
+  {
+    union
+      {
+        nint8_t u6_addr8[16];
+        nint16_t u6_addr16[8];
+        nint32_t u6_addr32[4];
+      } in6_u;
+#define s6_addr                 in6_u.u6_addr8
+#define s6_addr16               in6_u.u6_addr16
+#define s6_addr32               in6_u.u6_addr32
+  };
+
+#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+
+#define INET_ADDRSTRLEN 16
+#define INET6_ADDRSTRLEN 46
+
+
+struct ip6_hdr
+  {
+    union
+      {
+        struct ip6_hdrctl
+          {
+            nint32_t ip6_un1_flow;   /* 4 bits version, 8 bits TC,
+                                        20 bits flow-ID */
+            nint16_t ip6_un1_plen;   /* payload length */
+            nint8_t  ip6_un1_nxt;    /* next header */
+            nint8_t  ip6_un1_hlim;   /* hop limit */
+          } ip6_un1;
+        nint8_t ip6_un2_vfc;       /* 4 bits version, top 4 bits tclass */
+      } ip6_ctlun;
+    struct in6_addr ip6_src;      /* source address */
+    struct in6_addr ip6_dst;      /* destination address */
+  };
+
+#define ip6_vfc   ip6_ctlun.ip6_un2_vfc
+#define ip6_flow  ip6_ctlun.ip6_un1.ip6_un1_flow
+#define ip6_plen  ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt   ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim  ip6_ctlun.ip6_un1.ip6_un1_hlim
+#define ip6_hops  ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+/* This structure defines an ethernet arp header.  */
+
+/* ARP protocol opcodes. */
+#define ARPOP_REQUEST   1               /* ARP request.  */
+#define ARPOP_REPLY     2               /* ARP reply.  */
+#define ARPOP_RREQUEST  3               /* RARP request.  */
+#define ARPOP_RREPLY    4               /* RARP reply.  */
+#define ARPOP_InREQUEST 8               /* InARP request.  */
+#define ARPOP_InREPLY   9               /* InARP reply.  */
+#define ARPOP_NAK       10              /* (ATM)ARP NAK.  */
+
+/* See RFC 826 for protocol description.  ARP packets are variable
+   in size; the arphdr structure defines the fixed-length portion.
+   Protocol type values are the same as those for 10 Mb/s Ethernet.
+   It is followed by the variable-sized fields ar_sha, arp_spa,
+   arp_tha and arp_tpa in that order, according to the lengths
+   specified.  Field names used correspond to RFC 826.  */
+
+struct arphdr
+  {
+    nint16_t ar_hrd;          /* Format of hardware address.  */
+    nint16_t ar_pro;          /* Format of protocol address.  */
+    nint8_t ar_hln;               /* Length of hardware address.  */
+    nint8_t ar_pln;               /* Length of protocol address.  */
+    nint16_t ar_op;           /* ARP opcode (command).  */
+#if 0
+    /* Ethernet looks like this : This bit is variable sized
+       however...  */
+    nint8_t __ar_sha[ETH_ALEN];   /* Sender hardware address.  */
+    nint8_t __ar_sip[4];          /* Sender IP address.  */
+    nint8_t __ar_tha[ETH_ALEN];   /* Target hardware address.  */
+    nint8_t __ar_tip[4];          /* Target IP address.  */
+#endif
+  };
+
+/*
+ *      This is an Ethernet frame header.
+ */
+struct ethhdr {
+        nint8_t h_dest[ETH_ALEN];       /* destination eth addr */
+        nint8_t h_source[ETH_ALEN];     /* source ether addr    */
+        nint16_t          h_proto;                /* packet type ID field */
+};
+
+/*
+ * Ethernet Address Resolution Protocol.
+ *
+ * See RFC 826 for protocol description.  Structure below is adapted
+ * to resolving internet addresses.  Field names used correspond to
+ * RFC 826.
+ */
+struct  ether_arp {
+        struct  arphdr ea_hdr;          /* fixed-size header */
+        nint8_t arp_sha[ETH_ALEN];     /* sender hardware address */
+        nint8_t arp_spa[4];            /* sender protocol address */
+        nint8_t arp_tha[ETH_ALEN];     /* target hardware address */
+        nint8_t arp_tpa[4];            /* target protocol address */
+};
+#define arp_hrd ea_hdr.ar_hrd
+#define arp_pro ea_hdr.ar_pro
+#define arp_hln ea_hdr.ar_hln
+#define arp_pln ea_hdr.ar_pln
+#define arp_op  ea_hdr.ar_op
+
+
+
+
+/* ARP protocol HARDWARE identifiers. */
+#define ARPHRD_NETROM   0               /* From KA9Q: NET/ROM pseudo. */
+#define ARPHRD_ETHER    1               /* Ethernet 10/100Mbps.  */
+#define ARPHRD_EETHER   2               /* Experimental Ethernet.  */
+#define ARPHRD_AX25     3               /* AX.25 Level 2.  */
+#define ARPHRD_PRONET   4               /* PROnet token ring.  */
+#define ARPHRD_CHAOS    5               /* Chaosnet.  */
+#define ARPHRD_IEEE802  6               /* IEEE 802.2 Ethernet/TR/TB.  */
+#define ARPHRD_ARCNET   7               /* ARCnet.  */
+#define ARPHRD_APPLETLK 8               /* APPLEtalk.  */
+#define ARPHRD_DLCI     15              /* Frame Relay DLCI.  */
+#define ARPHRD_ATM      19              /* ATM.  */
+#define ARPHRD_METRICOM 23              /* Metricom STRIP (new IANA id).  */
+#define ARPHRD_IEEE1394 24              /* IEEE 1394 IPv4 - RFC 2734.  */
+#define ARPHRD_EUI64            27              /* EUI-64.  */
+#define ARPHRD_INFINIBAND       32              /* InfiniBand.  */
+
+
+#endif
+
index 6959576..e75b601 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Resource framework
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * Resource framework
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index 6478834..5307a90 100644 (file)
@@ -1,5 +1,24 @@
 /* Show output on displays.
  *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/*
  * Display interaction depends heavily on available hardware.
  * For this reason, the messages are formatted in the bottom half
  * of the 0cpm firmerware.  By defining different routines for
diff --git a/include/0cpm/snd.h b/include/0cpm/snd.h
new file mode 100644 (file)
index 0000000..3fce36f
--- /dev/null
@@ -0,0 +1,65 @@
+/* Sound calls and data types.
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef HEADER_SND
+#define HEADER_SND
+
+
+/* The channel devices that can carry sound */
+typedef enum {
+       SOUNDDEV_NONE = 0,
+       SOUNDDEV_HANDSET,
+       SOUNDDEV_HEADSET,
+       SOUNDDEV_SPEAKER,
+       SOUNDDEV_LINE
+} sounddev_t;
+
+
+/* The codec types that may be supported */
+typedef enum {
+       CODEC_G711A,
+       CODEC_G711MU
+} codec_t;
+
+
+/* Calls to change sound channels */
+
+void bottom_soundchannel_device (uint8_t chan, sounddev_t dev);
+void bottom_soundchannel_setvolume (uint8_t chan, uint8_t vol);
+uint8_t bottom_soundchannel_getvolume (uint8_t chan);
+
+/* Upcalls to indicate that sound can be inserted */
+
+uint16_t top_codec_can_play   (uint8_t chan, uint16_t samples);
+uint16_t top_codec_can_record (uint8_t chan, uint16_t samples);
+
+/* Calls to play or record through a codec */
+
+void bottom_codec_play_samplerate   (uint8_t chan, uint32_t samplerate);
+void bottom_codec_record_samplerate (uint8_t chan, uint32_t samplerate);
+
+int16_t bottom_codec_play   (uint8_t chan, codec_t codec, uint8_t *coded_samples, uint16_t coded_bytes, uint16_t samples);
+
+int16_t bottom_codec_record (uint8_t chan, codec_t codec, uint8_t *coded_samples, uint16_t coded_bytes, uint16_t samples);
+
+void bottom_codec_play_skip (codec_t codec, uint16_t samples);
+
+
+#endif
index b0a5ff6..a121c5a 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Timer drivers
  *
- * Timer drivers
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
@@ -16,6 +29,7 @@
  *   #define TIME_MSEC(x) ...
  *   #define TIME_SEC(x) ...
  *   #define TIME_BEOFRE(x,y) ...
+ *   #define TIME_BEFOREQ(x,y) ...
  * The former can be used as a parameter without pointers;
  * the TIME_xxx define such periods in terms of that time.
  */
@@ -32,6 +46,7 @@
 typedef struct irqtimer_type irqtimer_t;
 struct irqtimer_type {
        irq_t tmr_irq;
+       irqtimer_t *tmr_next;
        timing_t tmr_expiry;
 };
 
@@ -42,8 +57,10 @@ void irqtimer_restart (irqtimer_t *tmr, timing_t intval);
 void irqtimer_stop    (irqtimer_t *tmr);
 
 
-/* Top-half operations to manipulate timers */
-void top_timer_expiration (timing_t exptime);
+/* Top-half operations to manipulate timers; return the desired
+ * new timer setting to follow up after the expiration has
+ * taken place */
+timing_t top_timer_expiration (timing_t exptime);
 
 
 /* Bottom-half operations to manipulate the next timer interrupt */
diff --git a/include/bottom/blackfin.h b/include/bottom/blackfin.h
new file mode 100644 (file)
index 0000000..9fb85b0
--- /dev/null
@@ -0,0 +1,18 @@
+/* Blackfin-specific includes
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
diff --git a/include/bottom/devel.h b/include/bottom/devel.h
new file mode 100644 (file)
index 0000000..f0385fd
--- /dev/null
@@ -0,0 +1,31 @@
+/* Temporary settings during development
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+// TODO: The following nethandlers have not been implemented yet
+#include <stdlib.h>
+inline uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) { return NULL; }
+inline uint8_t *net_rtcp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) { return NULL; }
+inline uint8_t *net_sip (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) { return NULL; }
+inline uint8_t *net_mdns_resp_error (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) { return NULL; }
+inline uint8_t *net_mdns_resp_dyn (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) { return NULL; }
+inline uint8_t *net_mdns_resp_std (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) { return NULL; }
+inline uint8_t *net_mdns_query_error (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) { return NULL; }
+inline uint8_t *net_mdns_query_ok (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) { return NULL; }
+
index 6a199a4..ea6ac9f 100644 (file)
@@ -1,4 +1,22 @@
-/* Grandstream-specific definitions, split up per model where needed */
+/* Grandstream-specific definitions, split up per model where needed
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 
 #ifndef HEADER_GRANDSTREAM
 #define HEADER_GRANDSTREAM
@@ -32,7 +50,7 @@
 
 #pragma FAR(kbdisp)
 extern volatile uint8_t kbdisp;
-asm ("_kbdisp .set 0x666666");
+asm ("_kbdisp .set 0x666CDA");
 
 /* The network interface KSZ8842-16 is booted without EEPROM, so it
  * has no knowledge of anything -- specifically, no MAC address.
@@ -67,13 +85,22 @@ inline void ksz_memset16 (uint16_t ksz, uint8_t *mem) {
        mem [1] = ksz & 0xff;
 }
 
-
 #pragma FAR(flash_16)
-extern volatile uint16_t flash_16 [];
+extern volatile uint32_t flash_16 [];
 asm ("_flash_16 .set 0x200000");
 
-#endif
+#endif /* CONFIG_TARGET_GRANDSTREAM_BT20x || CONFIG_TARGET_GRANDSTREAM_BT10x */
+
+#if defined CONFIG_TARGET_GRANDSTREAM_BT20x
 
+#define HAVE_FLASH_PARTITIONS 1
+
+/* The MAC address is stored at byte offset 0x014006 */
+#define flash_offset_mymac 0x00a003
+
+void bottom_flash_get_mac (uint8_t mac [6]);
+
+#endif
 
 #endif
 
index 5ad2fa4..76aead7 100644 (file)
@@ -1,6 +1,20 @@
 /* HT162x includes
  *
- * From: Rick van Rein <rick@openfortress.nl>
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index 0191b23..c0fb5e3 100644 (file)
@@ -1,6 +1,20 @@
 /* Micrel KSZ8842 includes.
  *
- * From: Rick van Rein <rick@openfortress.nl>
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index d9b6065..0fa9d77 100644 (file)
@@ -1,3 +1,22 @@
+/* Includes for initial test developments on Linux (using tunnels)
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 
 #include <stdint.h>
 
index ad55dbc..18b0518 100644 (file)
@@ -1,11 +1,27 @@
-/*
- * tic55x bottom support definitions
+/* tic55x bottom support definitions
  *
- * Below:
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* 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 TIME_BEFOREQ(x,y)      (!(TIME_BEFORE((y),(x))))
 
 #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)
+#define TIME_MSEC(x)   (((uint32_t) (x)))
+#define TIME_SEC(x)    (((uint32_t) (x))*1000)
+#define TIME_MIN(x)    (((uint32_t) (x))*1000*60)
+#define TIME_HOUR(x)   (((uint32_t) (x))*1000*60*60)
+#define TIME_DAY(x)    (((uint32_t) (x))*1000*60*60*24)
 
 
 /* Critical region definitions */
 #define bottom_critical_region_begin() _disable_interrupts()
 #define bottom_critical_region_end()    _enable_interrupts()
 
+/* Mapping data from/to network format */
+#define htons(x) (x)
+#define htonl(x) (x)
+#define ntohs(x) (x)
+#define ntohl(x) (x)
+
+/* Misc utility functions */
+#define bzero(p,n) memset((p),0,(n))
+
 
 /* Following definitions are only available if BOTTOM is defined */
 
@@ -42,7 +68,10 @@ asm ("_IFR0 .set 0x0001");
 asm ("_IFR1 .set 0x0046");
 
 #define REGBIT_IER0_TINT0      4
+#define REGBIT_IER0_DMAC1      9
+#define REGBIT_IER0_INT0       2
 #define REGBIT_IER1_TINT1      6
+#define REGBIT_IER1_DMAC0      2
 
 extern volatile uint16_t IVPD, IVPH;
 asm ("_IVPD .set 0x0049");
@@ -81,14 +110,37 @@ asm ("_CE2_SEC2 .set 0x0829");
 asm ("_CE3_SEC1 .set 0x082a");
 asm ("_CE3_SEC2 .set 0x082b");
 
+/* EMIF SDRAM control registers */
+extern volatile uint16_t ioport SDC1, SDC2, SDRC1, SDRC2, SDX1, SDX2, CESCR1, CESCR2;
+asm ("_SDC1 .set 0x080c");
+asm ("_SDC2 .set 0x080d");
+asm ("_SDRC1 .set 0x080e");
+asm ("_SDRC2 .set 0x080f");
+asm ("_SDX1 .set 0x0810");
+asm ("_SDX2 .set 0x0811");
+asm ("_CESCR1 .set 0x0840");
+asm ("_CESCR2 .set 0x0841");
+
 /* 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_IDLEEN      14
 #define REGBIT_PCR_XIOEN       13
+#define REGBIT_PCR_RIOEN       12
+#define REGBIT_PCR_FSXM                11
+#define REGBIT_PCR_FSRM                10
+#define REGBIT_PCR_CLKXM       9
+#define REGBIT_PCR_CLKRM       8
+#define REGBIT_PCR_SCLKME      7
+#define REGBIT_PCR_CLKSSTAT    6
+#define REGBIT_PCR_DXSTAT      5
+#define REGBIT_PCR_DRSTAT      4
+#define REGBIT_PCR_FSXP                3
+#define REGBIT_PCR_FSRP                2
+#define REGBIT_PCR_CLKXP       1
+#define REGBIT_PCR_CLKRP       0
 
 #define REGVAL_PCR_CLKRP       0x01
 #define REGVAL_PCR_CLKXP       0x02
@@ -173,9 +225,10 @@ asm ("_PICR .set 0x9400");
 #define REGBIT_PICR_TIM0 0
 
 /* PLL configuration registers */
-extern volatile uint16_t ioport PLLCSR, PLLM, PLLDIV1, PLLDIV2, PLLDIV3;
+extern volatile uint16_t ioport PLLCSR, PLLM, PLLDIV0, PLLDIV1, PLLDIV2, PLLDIV3;
 asm ("_PLLCSR .set 0x1c80");
 asm ("_PLLM .set 0x1c88");
+asm ("_PLLDIV0 .set 0x1c8a");
 asm ("_PLLDIV1 .set 0x1c8c");
 asm ("_PLLDIV2 .set 0x1c8e");
 asm ("_PLLDIV3 .set 0x1c90");
@@ -197,6 +250,7 @@ asm ("_PLLDIV3 .set 0x1c90");
 
 #define REGVAL_PLLCSR_PLLEN            0x0001
 #define REGVAL_PLLCSR_PLLRST           0x0008
+#define REGVAL_PLLCSR_LOCK             0x0020
 #define REGVAL_PLLCSR_STABLE           0x0040
 
 #define REGVAL_PLLDIVx_DxEN            0x8000
@@ -204,5 +258,218 @@ asm ("_PLLDIV3 .set 0x1c90");
 #define REGVAL_PLLDIVx_PLLDIVx_2       0x0001
 #define REGVAL_PLLDIVx_PLLDIVx_4       0x0003
 
+/* McBSP1 configuration registers */
+extern volatile uint16_t ioport SPCR1_1, SPCR2_1, SRGR1_1, SRGR2_1;
+extern volatile uint16_t ioport MCR1_1, MCR2_1;
+extern volatile uint16_t ioport RCR1_1, RCR2_1, XCR1_1, XCR2_1;
+extern volatile uint16_t ioport DXR1_1, DRR1_1;
+asm ("_SPCR1_1 .set 0x2c04");
+asm ("_SPCR2_1 .set 0x2c05");
+asm ("_RCR1_1 .set 0x2c06");
+asm ("_RCR2_1 .set 0x2c07");
+asm ("_XCR1_1 .set 0x2c08");
+asm ("_XCR2_1 .set 0x2c09");
+asm ("_SRGR1_1 .set 0x2c0a");
+asm ("_SRGR2_1 .set 0x2c0b");
+asm ("_MCR1_1 .set 0x2c0c");
+asm ("_MCR2_1 .set 0x2c0d");
+asm ("_DXR1_1 .set 0x2c02");
+asm ("_DRR1_1 .set 0x2c02");
+
+#define REGVAL_SPCR1_CLKSTP_WITHDELAY  0x1800
+#define REGVAL_SPCR1_RRST_NOTRESET     0x0001
+#define REGVAL_SPCR2_FRST_NOTRESET     0x0080
+#define REGVAL_SPCR2_GRST_NOTRESET     0x0040
+#define REGVAL_SPCR2_XRST_NOTRESET     0x0001
+
+#define REGVAL_SRGR1_FWID_1            0x0100
+#define REGVAL_SRGR1_CLKGDIV_1         0x0001
+#define REGVAL_SRGR1_CLKGDIV_4         0x0004
+#define REGVAL_SRGR1_CLKGDIV_5         0x0005
+#define REGVAL_SRGR1_CLKGDIV_15                0x000f
+#define REGVAL_SRGR1_CLKGDIV_30                0x001e
+#define REGVAL_SRGR2_GSYNC             0x8000
+#define REGVAL_SRGR2_CLKSP             0x4000
+#define REGVAL_SRGR2_CLKSM             0x2000
+#define REGVAL_SRGR2_FSGM              0x1000
+#define REGVAL_SRGR2_FPER_255          255
+#define REGVAL_SRGR2_FPER_511          511
+#define REGVAL_SRGR2_FPER_999          999
+#define REGVAL_SRGR2_FPER_1535         1535
+
+/* I2C configuration registers */
+
+extern volatile uint16_t ioport I2CPSC, I2CCLKL, I2CCLKH, I2COAR;
+extern volatile uint16_t ioport I2CMDR, I2CSTR, I2CIER, I2CISRC;
+extern volatile uint16_t ioport I2CSAR, I2CCNT, I2CDXR, I2CDRR;
+
+asm ("_I2CPSC .set 0x3c0c");
+asm ("_I2CCLKL .set 0x3c03");
+asm ("_I2CCLKH .set 0x3c04");
+asm ("_I2COAR .set 0x3c00");
+asm ("_I2CMDR .set 0x3c09");
+asm ("_I2CSTR .set 0x3c02");
+asm ("_I2CIER .set 0x3c01");
+asm ("_I2CISRC .set 0x3c0a");
+asm ("_I2CSAR .set 0x3c07");
+asm ("_I2CCNT .set 0x3c05");
+asm ("_I2CDXR .set 0x3c08");
+asm ("_I2CDRR .set 0x3c06");
+
+#define REGVAL_I2CMDR_NACKMOD  0x8000
+#define REGVAL_I2CMDR_FREE     0x4000
+#define REGVAL_I2CMDR_STT      0x2000
+#define REGVAL_I2CMDR_IDLEEN   0x1000
+#define REGVAL_I2CMDR_STP      0x0800
+#define REGVAL_I2CMDR_MST      0x0400
+#define REGVAL_I2CMDR_TRX      0x0200
+#define REGVAL_I2CMDR_XA       0x0100
+#define REGVAL_I2CMDR_RM       0x0080
+#define REGVAL_I2CMDR_DLB      0x0040
+#define REGVAL_I2CMDR_NORESET  0x0020
+#define REGVAL_I2CMDR_STB      0x0010
+#define REGVAL_I2CMDR_FDF      0x0008
+#define REGVAL_I2CMDR_BC_8     0x0000
+
+#define REGVAL_I2CIER_XRDY     0x0010
+#define REGVAL_I2CIER_RRDY     0x0008
+#define REGVAL_I2CIER_ARDY     0x0004
+#define REGVAL_I2CIER_NACK     0x0002
+#define REGVAL_I2CIER_AL       0x0001
+
+#define REGVAL_I2CSTR_NACKSN   0x2000
+#define REGVAL_I2CSTR_BB       0x1000
+#define REGVAL_I2CSTR_RSFULL   0x0800
+#define REGVAL_I2CSTR_XSMT     0x0400
+#define REGVAL_I2CSTR_AAS      0x0200
+#define REGVAL_I2CSTR_AD0      0x0100
+#define REGVAL_I2CSTR_XRDY     0x0010
+#define REGVAL_I2CSTR_RRDY     0x0008
+#define REGVAL_I2CSTR_ARDY     0x0004
+#define REGVAL_I2CSTR_NACK     0x0002
+#define REGVAL_I2CSTR_AL       0x0001
+
+#define REGVAL_I2COAR          0x005a
+
+/* DMA configuration */
+
+extern volatile uint16_t ioport DMAGCR, DMAGTCR;
+
+extern volatile uint16_t ioport DMACSDP_0, DMACCR_0, DMACICR_0, DMACSR_0;
+extern volatile uint16_t ioport DMACSSAL_0, DMACSSAU_0, DMACDSAL_0, DMACDSAU_0;
+extern volatile uint16_t ioport DMACEN_0, DMACFN_0, DMACSEI_0, DMACSFI_0, DMACDEI_0, DMACDFI_0;
+extern volatile uint16_t ioport DMACSAC_0, DMACDAC_0;
+
+extern volatile uint16_t ioport DMACSDP_1, DMACCR_1, DMACICR_1, DMACSR_1;
+extern volatile uint16_t ioport DMACSSAL_1, DMACSSAU_1, DMACDSAL_1, DMACDSAU_1;
+extern volatile uint16_t ioport DMACEN_1, DMACFN_1, DMACSEI_1, DMACSFI_1, DMACDEI_1, DMACDFI_1;
+extern volatile uint16_t ioport DMACSAC_1, DMACDAC_1;
+
+asm ("_DMAGCR .set 0x0e00");
+asm ("_DMAGTCR .set 0x0e01");
+
+asm ("_DMACSDP_0 .set 0x0c00");
+asm ("_DMACCR_0 .set 0x0c01");
+asm ("_DMACICR_0 .set 0x0c02");
+asm ("_DMACSR_0 .set 0x0c03");
+asm ("_DMACSSAL_0 .set 0x0c04");
+asm ("_DMACSSAU_0 .set 0x0c05");
+asm ("_DMACDSAL_0 .set 0x0c06");
+asm ("_DMACDSAU_0 .set 0x0c07");
+asm ("_DMACEN_0 .set 0x0c08");
+asm ("_DMACFN_0 .set 0x0c09");
+asm ("_DMACSEI_0 .set 0x0c0b");
+asm ("_DMACSFI_0 .set 0x0c0a");
+asm ("_DMACSDEI_0 .set 0x0c0e");
+asm ("_DMACSDFI_0 .set 0x0c0f");
+asm ("_DMACSAC_0 .set 0x0c0c");
+asm ("_DMACDAC_0 .set 0x0c0d");
+
+asm ("_DMACSDP_1 .set 0x0c20");
+asm ("_DMACCR_1 .set 0x0c21");
+asm ("_DMACICR_1 .set 0x0c22");
+asm ("_DMACSR_1 .set 0x0c23");
+asm ("_DMACSSAL_1 .set 0x0c24");
+asm ("_DMACSSAU_1 .set 0x0c25");
+asm ("_DMACDSAL_1 .set 0x0c26");
+asm ("_DMACDSAU_1 .set 0x0c27");
+asm ("_DMACEN_1 .set 0x0c28");
+asm ("_DMACFN_1 .set 0x0c29");
+asm ("_DMACSEI_1 .set 0x0c2b");
+asm ("_DMACSFI_1 .set 0x0c2a");
+asm ("_DMACSDEI_1 .set 0x0c2e");
+asm ("_DMACSDFI_1 .set 0x0c2f");
+asm ("_DMACSAC_1 .set 0x0c2c");
+asm ("_DMACDAC_1 .set 0x0c2d");
+
+#define REGVAL_DMAGCR_FREE     0x0004
+#define REGVAL_DMAGTCR_PTE     0x0008
+#define REGVAL_DMAGTCR_ETE     0x0004
+#define REGVAL_DMAGTCR_ITE1    0x0002
+#define REGVAL_DMAGTCR_ITE0    0x0001
+#define REGVAL_DMACCR_ENDPROG  0x0800
+#define REGVAL_DMACCR_WP       0x0400
+#define REGVAL_DMACCR_REPEAT   0x0200
+#define REGVAL_DMACCR_AUTOINIT 0x0100
+#define REGVAL_DMACCR_EN       0x0080
+#define REGVAL_DMACCR_PRIO     0x0040
+#define REGVAL_DMACCR_FS       0x0020
+#define REGVAL_DMACCR_DSTAMODE_CONST   0x0000
+#define REGVAL_DMACCR_DSTAMODE_POSTINC 0x4000
+#define REGVAL_DMACCR_DSTAMODE_1INDEX  0x8000
+#define REGVAL_DMACCR_DSTAMODE_2INDEX  0xc000
+#define REGVAL_DMACCR_SRCAMODE_CONST   0x0000
+#define REGVAL_DMACCR_SRCAMODE_POSTINC 0x1000
+#define REGVAL_DMACCR_SRCAMODE_1INDEX  0x2000
+#define REGVAL_DMACCR_SRCAMODE_2INDEX  0x3000
+#define REGVAL_DMACCR_SYNC_NOEVENT     0x0000
+#define REGVAL_DMACCR_SYNC_MCBSP0_REV  0x0001
+#define REGVAL_DMACCR_SYNC_MCBSP0_TEV  0x0002
+#define REGVAL_DMACCR_SYNC_MCBSP1_REV  0x0005
+#define REGVAL_DMACCR_SYNC_MCBSP1_TEV  0x0006
+#define REGVAL_DMACCR_SYNC_MCBSP2_REV  0x0009
+#define REGVAL_DMACCR_SYNC_MCBSP2_TEV  0x000a
+#define REGVAL_DMACCR_SYNC_UART_REV    0x000b
+#define REGVAL_DMACCR_SYNC_UART_TEV    0x000c
+#define REGVAL_DMACCR_SYNC_TIMER0      0x000d
+#define REGVAL_DMACCR_SYNC_TIMER1      0x000e
+#define REGVAL_DMACCR_SYNC_INT0                0x0010
+#define REGVAL_DMACCR_SYNC_INT1                0x0011
+#define REGVAL_DMACCR_SYNC_INT2                0x0012
+#define REGVAL_DMACCR_SYNC_INT3                0x0013
+#define REGVAL_DMACCR_SYNC_I2C_REV     0x0013
+#define REGVAL_DMACCR_SYNC_I2C_TEV     0x0014
+#define REGVAL_DMACICR_AERRIE          0x0080
+#define REGVAL_DMACICR_BLOCKIE         0x0020
+#define REGVAL_DMACICR_LASTIE          0x0010
+#define REGVAL_DMACICR_FRAMEIE         0x0008
+#define REGVAL_DMACICR_HALFIE          0x0004
+#define REGVAL_DMACICR_DROPIE          0x0002
+#define REGVAL_DMACICR_TIMEOUTIE       0x0001
+#define REGVAL_DMACSR_AERR             0x0080
+#define REGVAL_DMACSR_SYNC             0x0040
+#define REGVAL_DMACSR_BLOCK            0x0020
+#define REGVAL_DMACSR_LAST             0x0010
+#define REGVAL_DMACSR_FRAME            0x0008
+#define REGVAL_DMACSR_HALF             0x0004
+#define REGVAL_DMACSR_DROP             0x0002
+#define REGVAL_DMACSR_TIMEOUT          0x0001
+#define REGVAL_DMACSDP_DSTBEN_DISABLE  0x0000
+#define REGVAL_DMACSDP_DSTBEN_BURST    0x8000
+#define REGVAL_DMACSDP_DSTPACK         0x2000
+#define REGVAL_DMACSDP_DST_DARAM0      0x0000
+#define REGVAL_DMACSDP_DST_DARAM1      0x0200
+#define REGVAL_DMACSDP_DST_EMIF                0x0400
+#define REGVAL_DMACSDP_DST_PERIPH      0x0600
+#define REGVAL_DMACSDP_SRCBEN_DISABLE  0x0000
+#define REGVAL_DMACSDP_SRCB EN_ENABLE  0x0100
+#define REGVAL_DMACSDP_SRCPACK         0x0040
+#define REGVAL_DMACSDP_SRC_DARAM0      0x0000
+#define REGVAL_DMACSDP_SRC_DARAM1      0x0004
+#define REGVAL_DMACSDP_SRC_EMIF                0x0008
+#define REGVAL_DMACSDP_SRC_PERIPH      0x000c
+#define REGVAL_DMACSDP_DATATYPE_8BIT   0x0000
+#define REGVAL_DMACSDP_DATATYPE_16BIT  0x0001
+#define REGVAL_DMACSDP_DATATYPE_32BIT  0x0002
 
 #endif
index c2d7886..be5731d 100644 (file)
@@ -1,4 +1,22 @@
-/* Backup for unsupportive compiles */
+/* Backup for unsupportive compiles
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 
 typedef enum {
        false = 0,
index 2689bb0..d7ef4a3 100644 (file)
@@ -1,10 +1,12 @@
 
-objs-bottom-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += src/driver/tic55x/grandstream-bt20x.o src/driver/ht162x.o src/driver/ksz8842.o
+objs-bottom-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += src/driver/tic55x/grandstream-bt20x.o src/driver/ht162x.o src/driver/ksz8842.o src/driver/tlv320aic2x.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
+
+metavars-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += SYSCLK1_TO_MS_DIVIDER=122880
+# metavars-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += SYSCLK1_TO_MS_DIVIDER=61440
 
 includes-$(CONFIG_TARGET_GRANDSTREAM) += bottom/grandstream.h
index e69de29..2fc013e 100644 (file)
@@ -0,0 +1,19 @@
+/* Si3210 ATA chip driver.
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
index 41ae117..2e7a0a5 100644 (file)
@@ -1,6 +1,23 @@
 /* ht162x.c -- driver for Holtek 162x chips
  *
- * This is a general driver for Holtek 162x LCD driver chips.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This is a general driver for Holtek 162x LCD driver chips.
  * It is designed to output bits serially, using a few low-level
  * routines elsewhere that depend on how the hardware is wired.
  * 
index fde9c62..78aeaa4 100644 (file)
@@ -1,6 +1,24 @@
 /* Micrel KSZ8842-16 drivers.  Probably suitable for -32 as well.
  *
- * This driver uses a few low-level routines that should be part
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This driver uses a few low-level routines that should be part
  * of the architecture definition of a particular phone:
  *  - kszmap16() maps 16-bit values between CPU and KSZ endianity
  *  - kszmap32() maps 32-bit values between CPU and KSZ endianity
@@ -77,7 +95,7 @@ void ksz8842_interrupt_handler (void) {
        //
        // See if more frames can be sent or received
        if (ifr & kszmap16 (REGVAL_KSZ8842_ISR_TXIS)) {
-               top_network_can_send ();
+               //TODO// top_network_can_send ();
        }
        if (ifr & kszmap16 (REGVAL_KSZ8842_ISR_RXIS)) {
                top_network_can_recv ();
index facf645..7971f32 100644 (file)
@@ -1 +1,18 @@
-/* TODO -- the most-used network chip in SIP phones */
+/* TODO -- the most-used network chip in SIP phones
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
index e69de29..55a9203 100644 (file)
@@ -0,0 +1,18 @@
+/* Drivers for TI's tic54x DSP chips.
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
index e69de29..d50bfd7 100644 (file)
@@ -0,0 +1,18 @@
+/* Visba3 driver (for Linksys SPA devices)
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
index 9c90d01..115a2ad 100644 (file)
@@ -28,7 +28,7 @@ Diverting the problem
 ---------------------
 
 It is difficult, but not impossible to avoid getting into trouble
-with either or both licenses.  We first summerise them, and than
+with either or both licenses.  We first summerise them, and then
 detail the options further down.
 
 1. Do not release your modified code to anyone
@@ -62,14 +62,15 @@ not suffer from it.
 >>> ad 2. Unaltered binaries
 
        You could make the choice to use unaltered binaries
-       that you can download from our website.  This could
-       imply that you would have to clone a hardware
+       that your users can download from our website.  This
+       could imply that you would have to clone a hardware
        platform.  Please inform yourself of the possible
        copyright infringements that you are risking before
        you do this.  We reverse engineered phones, which is
        not an offense as we are not copying them, but you
-       might run into problems if you did.  Read (ad 2) for
-       a way out.
+       could run into problems if you did.  Read (ad 3) and
+       (ad 4) for solutions that help you to binaries for
+       your own hardware.
 
 >>> ad 3. Submit changes
 
diff --git a/src/driver/tic55x/dma.c b/src/driver/tic55x/dma.c
new file mode 100644 (file)
index 0000000..2faaa5b
--- /dev/null
@@ -0,0 +1,31 @@
+/* TIC55x direct memory access
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* The tic55x architecture has 6 DMA channels, which will be used
+ * as follows:
+ *
+ *  0 - HIPRI - Read  sound from the current microphone input
+ *  1 - HIPRI - Write sound to   the current speaker    output
+ *  2 - UNUSE - Read  packet data from the network?  Nope.
+ *  3 - UNUSE - Write packet data to   the network?  Nope.
+ *  4 - UNUSE
+ *  5 - UNUSE
+ */
+
index aa469d9..e4881f6 100644 (file)
@@ -1,4 +1,21 @@
-/* GPIO driver for tic55x */
+/* GPIO driver for tic55x
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 #include <stdint.h>
 #include <stdbool.h>
index 82f62b1..d12db66 100644 (file)
@@ -1,4 +1,21 @@
-/* Grandstream BT20x driver as an extension to the tic55x driver */
+/* Grandstream BT20x driver as an extension to the tic55x driver
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 
 #include <stdbool.h>
@@ -13,6 +30,8 @@
 #include <0cpm/kbd.h>
 #include <0cpm/app.h>
 #include <0cpm/show.h>
+#include <0cpm/flash.h>
+#include <0cpm/snd.h>
 
 #include <bottom/ht162x.h>
 #include <bottom/ksz8842.h>
@@ -27,6 +46,7 @@ interrupt void tic55x_int0_isr (void) {
        ksz8842_interrupt_handler ();
 }
 
+#if 0
 interrupt void tic55x_int1 (void) {
        tic55x_top_has_been_interrupted = true;
        //TODO//
@@ -41,6 +61,278 @@ interrupt void tic55x_int3 (void) {
        tic55x_top_has_been_interrupted = true;
        //TODO//
 }
+#endif
+
+
+
+/******** FLASH PARTITION ACCESS ********/
+
+
+/* An external definition (usually in phone-specific code)
+ * contains an array of at least one entry of flashpart
+ * structures.  Only the last will have the FLASHPART_FLAG_LAST
+ * flag set.
+ *
+ * There will usually be one partition with name ALLFLASH.BIN
+ * that covers the entire flash memory, including things that
+ * may not actually be in any partition.  Usually, this is the
+ * last entry in the flash partition table.
+ */
+struct flashpart bottom_flash_partition_table [] = {
+       { FLASHPART_FLAG_LAST, "ALLFLASH.BIN", 0, 4096 }
+};
+
+
+/* Read a 512-byte block from flash.
+ * The return value indicates success.
+ */
+bool bottom_flash_read (uint16_t blocknr, uint8_t data [512]) {
+       uint32_t flashidx;
+       uint16_t ctr = 0;
+       if (blocknr >= 4096) {
+               return false;
+       }
+       flashidx = ((uint32_t) blocknr) * 256;
+       while (ctr < 512) {
+               uint16_t sample = flash_16 [flashidx];
+               flashidx += 1;
+               // data [ctr++] = (sample >> 24) & 0xff;
+               // data [ctr++] = (sample >> 16) & 0xff;
+               data [ctr++] = (sample >>  8) & 0xff;
+               data [ctr++] =  sample        & 0xff;
+       }
+       return true;
+}
+
+
+/* Write a 512-byte block to flash.  It is assumed that this
+ * is done sequentially; any special treatment for a header
+ * page will be done by the bottom layer, not the top.
+ * The return value indicates success.
+ */
+bool boot_flash_write (uint16_t blocknr, uint8_t data [512]) {
+       return false;
+}
+
+
+/* Retrieve the current phone's MAC address from Flash.
+ */
+void bottom_flash_get_mac (uint8_t mac [6]) {
+       uint32_t flashidx = flash_offset_mymac;
+       uint16_t ctr = 0;
+       while (ctr < 6) {
+               uint16_t sample = flash_16 [flashidx];
+               flashidx++;
+               mac [ctr++] = (sample >> 8) & 0xff;
+               mac [ctr++] =  sample       & 0xff;
+       }
+}
+
+
+
+/******** TLV320AIC20K PROGRAMMING ACCESS OVER I2C ********/
+
+
+/* The codec can be programmed over I2C, so the low-level routines
+ * for driving the codec end up passing bytes over I2C.  The
+ * procedure of cycling through subregisters is not performed here.
+ */
+
+void tlv320aic2x_setreg (uint8_t channel, uint8_t reg, uint8_t val) {
+       // Wait as long as the bus is busy
+// bottom_led_set (LED_IDX_SPEAKERPHONE, 0);
+// bottom_led_set (LED_IDX_BACKLIGHT, 1);
+       while (I2CSTR & REGVAL_I2CSTR_BB) {
+               ;
+       }
+       // Set transmission mode for 2 bytes to "channel"
+       I2CSAR = 0x40 | channel;
+       //TODO// I2CSAR = 0x00; // Broadcast
+       I2CCNT = 2;
+       I2CDXR = reg;
+       // Send the register index
+       // Initiate the transfer by setting STT and STP flags
+       I2CMDR = REGVAL_I2CMDR_TRX | REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STT | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
+       // Wait for the START condition to occur
+// bottom_led_set (LED_IDX_HANDSET, 1);
+       while (I2CMDR & REGVAL_I2CMDR_STT) {
+               ;
+       }
+// bottom_led_set (LED_IDX_HANDSET, 0);
+       // Wait until the I2C bus is ready, then send the value
+// bottom_led_set (LED_IDX_SPEAKERPHONE, 1);
+       while (!(I2CSTR & REGVAL_I2CSTR_XRDY)) {
+               if (I2CSTR & REGVAL_I2CSTR_NACK) {
+                       I2CSTR = REGVAL_I2CSTR_NACK;
+                       I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
+                       return;
+               }
+       }
+// bottom_led_set (LED_IDX_SPEAKERPHONE, 0);
+       I2CDXR = val;
+       // Wait for the STOP condition to occur
+       while (I2CMDR & REGVAL_I2CMDR_STP) {
+               ;
+       }
+// bottom_led_set (LED_IDX_BACKLIGHT, 0);
+}
+
+uint8_t tlv320aic2x_getreg (uint8_t channel, uint8_t reg) {
+       uint8_t val;
+uint32_t ctr;
+// bottom_led_set (LED_IDX_BACKLIGHT, 1);
+// bottom_led_set (LED_IDX_HANDSET, 0);
+       // Wait as long as the bus is busy
+       while (I2CSTR & REGVAL_I2CSTR_BB) {
+               ;
+       }
+       // Set transmission mode for 1 byte to "channel"
+       I2CSAR = 0x40 | channel;
+       //TODO// I2CSAR = 0x00; // Broadcast
+       I2CCNT = 1;
+       I2CDXR = reg;
+       // Send the register index
+       // Initiate the transfer by setting STT flag, but withhold STP
+       I2CMDR = REGVAL_I2CMDR_TRX | REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STT | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
+       // Wait until the START condition has occurred
+       while (I2CMDR & REGVAL_I2CMDR_STT) {
+               ;
+       }
+       // ...send address and write mode bit...
+// bottom_led_set (LED_IDX_HANDSET, 1);
+       // Wait until ready to setup for receiving
+       while (I2CMDR & REGVAL_I2CMDR_STP) {
+               if (I2CSTR & REGVAL_I2CSTR_NACK) {
+                       I2CSTR = REGVAL_I2CSTR_NACK;
+                       I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
+                       return 0;
+               }
+       }
+// bottom_led_set (LED_IDX_HANDSET, 0);
+       I2CCNT = 1;
+       // Restart with STT flag, also permit stop with STP; do not set TRX
+       I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STT | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
+       // ...recv val...
+       while (!(I2CSTR & REGVAL_I2CSTR_RRDY)) {
+#if 0
+               if (I2CSTR & REGVAL_I2CSTR_NACK) {
+                       I2CSTR = REGVAL_I2CSTR_NACK;
+                       // I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
+                       // return 0;
+               }
+#endif
+               ;
+       }
+       val = I2CDRR;
+// bottom_led_set (LED_IDX_BACKLIGHT, 0);
+       return val;
+}
+
+
+/******** TLV320AIC20K DATA ACCESS OVER MCBSP1 ********/
+
+
+#define BUFSZ (64*4)
+
+extern volatile uint16_t samplebuf_play   [BUFSZ];
+extern volatile uint16_t samplebuf_record [BUFSZ];
+
+extern volatile uint16_t available_play;
+extern volatile uint16_t available_record;
+
+extern volatile uint16_t threshold_play;
+extern volatile uint16_t threshold_record;
+
+
+/* TODO: RAW CODEC FUNCTIONS: ASSUMING ALWAYS U-LAW and A-LAW, PLAIN COPY */
+
+/* Copy encoded samples to plain samples */
+int16_t codec_decode (codec_t codec, uint8_t *in, uint16_t inlen, uint16_t *out, uint16_t outlen) {
+       while ((inlen > 0) && (outlen > 0)) {
+               *out++ = *in++ << 8;
+               inlen--;
+               outlen--;
+       }
+       return inlen - outlen;
+}
+
+/* Copy plain samples to encoded samples */
+int16_t codec_encode (codec_t codec, uint16_t *in, uint16_t inlen, uint8_t *out, uint16_t outlen) {
+       while ((inlen > 0) && (outlen > 0)) {
+               *out++ = *in++ >> 8;
+               inlen--;
+               outlen--;
+       }
+       return outlen - inlen;
+}
+
+/* Set a frequency divisor for the intended sample rate */
+void tlv320aic2x_set_samplerate (uint32_t samplerate) {
+       samplerate = 12288000 / samplerate;
+       if (samplerate >= 4096) {
+               samplerate = 4096;
+       } else if (samplerate == 0) {
+               samplerate = 1;
+       }
+       SRGR2_1 = REGVAL_SRGR2_CLKSM | REGVAL_SRGR2_FSGM | ((samplerate - 1) & 0x0fff);
+}
+
+/* A full frame of 64 samples has been played.  See if another is availabe,
+ * otherwise disable DMA until a dmahint_play() restarts it.
+ */
+interrupt void tic55x_dmac0_isr (void) {
+       uint16_t irq = DMACSR_0;
+       uint16_t toplay;
+       tic55x_top_has_been_interrupted = true;
+       if ((available_play -= 64) < 64) {
+               DMACCR_0 &= ~REGVAL_DMACCR_EN;
+       }
+       toplay = BUFSZ - available_play;
+       if (BUFSZ - available_play > threshold_play) {
+               //TODO: Lower toplay if it exceeds the buffer size
+               // top_can_play (available_play);
+               top_can_play (64);
+       }
+}
+
+/* A full frame of 64 samples has been recorded.  See if space exists for
+ * another, otherwise disable DMA until a dmahint_record() restarts it.
+ */
+interrupt void tic55x_dmac1_isr (void) {
+       uint16_t irq = DMACSR_1;
+       tic55x_top_has_been_interrupted = true;
+       if ((available_record += 64) >= (BUFSZ - 64)) {
+               DMACCR_1 &= ~REGVAL_DMACCR_EN;
+       }
+       if (available_record > threshold_record) {
+               //TODO: Lower value if it exceeds the buffer size
+               // top_can_record (availabl_record);
+               top_can_record (64);
+       }
+}
+
+/* New data has been written for playback.  As a result, it may
+ * be possible to restart DMA channel 0 if it was disabled.
+ */
+void dmahint_play (void) {
+       if (available_play >= 64) {
+               if (!(DMACCR_0 & REGVAL_DMACCR_EN)) {
+                       DMACCR_0 |= REGVAL_DMACCR_EN;
+               }
+       }
+}
+
+/* Data has been removed from what was recorded.  As a result,
+ * it may be possible to restart DMA channel 1 if it was disabled.
+ */
+void dmahint_record (void) {
+       if (available_record <= (BUFSZ - 64)) {
+               if (!(DMACCR_1 & REGVAL_DMACCR_EN)) {
+                       DMACCR_1 |= REGVAL_DMACCR_EN;
+               }
+       }
+}
+
 
 
 /******** HT162x LCD DRIVER LOW-LEVEL FUNCTIONS ********/
@@ -174,6 +466,7 @@ void ht162x_led_set (uint8_t lcdidx, led_colour_t col, bool notify) {
        }
 }
 
+
 /******** BOTTOM FUNCTIONS FOR LEDS AND BUTTONS ********/
 
 
@@ -187,7 +480,12 @@ void bottom_led_set (led_idx_t ledidx, led_colour_t col) {
                ht162x_led_set (11, col, true);
                break;
        case LED_IDX_MESSAGE:
-               //TODO: Figure out which pin -- incorrectly change backlight
+               if (col != 0) {
+                       asm (" bset xf");
+               } else {
+                       asm (" bclr xf");
+               }
+               break;
        case LED_IDX_BACKLIGHT:
                // Set bit DXSTAT=5 in PCR=0x2812 to 1/0
                if (col != 0) {
@@ -403,8 +701,49 @@ void bottom_show_ip4 (app_level_t level, uint8_t bytes [4]) {
        bt200_display_showtxt (level, ip, 0x07);
 }
 
-void bottom_show_ip6 (app_level_t level, uint16_t bytes [8]) {
-       ;       // Impossible, skip
+/* Print an IPv6 address, as far as this is possible, on the display
+ *  - Remove the prefix /64 as it is widely known
+ *  -TODO- If middle word is 0xfffe, remove it, display the rest, set dot #2
+ *  -TODO- If first word is 0x0000, remove it, display the rest, set dot #1
+ *  -TODO- If last word is 0x0001, remove it, display the rest, set dot #3
+ *  - If nothing else is possible, use 6 bits per digit, dots and last digit blanc
+void bottom_show_ip6 (app_level_t level, uint16_t words [8]) {
+       // TODO: Extra cases; for now, just dump 6 bits per 7-segment display
+       uint8_t idxi;
+       uint8_t idxo;
+       uint8_t shfi;
+       uint8_t shfo;
+       ht162x_led_set (12, 0, false);
+       ht162x_led_set ( 9, 0, false);
+       ht162x_led_set ( 6, 0, false);
+       for (idxo = 14; idxo >= 3; idxo--) {
+               ht162x_dispdata [idxo] &= 0x10;
+       }
+       shfi = 6;
+       shfo = 4;
+       idxi = 4;
+       idxo = 14;
+       while (idxi < 8) {
+               uint8_t twobits = (words [idxi] >> shfi) & 0x03;
+               twobits << shfo;
+               if (twobits & 0x10) {
+                       twobits += 0x80 - 0x10; // bit 7 replaces bit 4
+               }
+               ht162x_dispdata [idxo] |= (twobits << shfo);
+               if (shfi > 0) {
+                       shfi -= 2;
+               } else {
+                       shfi = 6;
+                       idxi++;
+               }
+               if (shfo > 0) {
+                       shfo -= 2;
+               } else {
+                       shfo = 5;
+                       idxo--;
+               }
+       }
+       ht162x_dispdata_notify (14, 3);
 }
 
 /* A list of fixed messages, matching the fixed_msg_t values */
@@ -441,27 +780,42 @@ void bottom_show_voicemail (app_level_t level, uint16_t new, uint16_t old) {
 
 /******** BOTTOM LEVEL MAIN PROGRAM ********/
 
-
 /* Setup the connectivity of the TIC55x as used on Grandstream BT20x */
 void main (void) {
        uint16_t idx;
        led_colour_t led = LED_STABLE_ON;
        //
-       // PLL setup: Crystal is 16.384 MHz, increase that a bit
-       //TODO: Possible in theory, but doesn't run and sinusoidal in practice
-       //      At lower PLLM factors, the sine is larger and clips to squarish
-       //TODO// PLLM = REGVAL_PLLM_TIMES_15;
-       //TODO// PLLCSR &= ~REGVAL_PLLCSR_PLLRST;
-       //TODO// while (!(PLLCSR & REGVAL_PLLCSR_STABLE)) {
-       //TODO//        ;
-       //TODO// }
-       //TODO// PLLDIV1 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_4;
-       //TODO// PLLDIV2 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_4;
+       // PLL setup: Crystal is 16.384 MHz, increase that 15x
+       // 1. Switch to bypass mode by setting the PLLEN bit to 0.
+       PLLCSR &= ~REGVAL_PLLCSR_PLLEN;
+       // 2. Set the PLL to its reset state by setting the PLLRST bit to 1.
+       PLLCSR |= REGVAL_PLLCSR_PLLRST;
+       // 3. Change the PLL setting through the PLLM and PLLDIV0 bits.
+       PLLM = REGVAL_PLLM_TIMES_15;
+       PLLDIV0 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_1;
+       // 4. Wait for 1 Âµs.
+       { int ctr = 1000; while (ctr--) ; }
+       // 5. Release the PLL from its reset state by setting PLLRST to 0.
+       PLLCSR &= ~REGVAL_PLLCSR_PLLRST;
+       // 6. Wait for the PLL to relock by polling the LOCK bit or by setting up a LOCK interrupt.
+       while ((PLLCSR & REGVAL_PLLCSR_LOCK) == 0) {
+               /* wait */ ;
+       }
+       // 7. Switch back to PLL mode by setting the PLLEN bit to 1.
+       PLLCSR |= REGVAL_PLLCSR_PLLEN;
+       PLLDIV1 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_2;
+       PLLDIV2 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_4;
        //TODO// PLLDIV3 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_4;
        //TODO// PLLCSR |= REGVAL_PLLCSR_PLLEN;
+       // Now we have:
+       //      CPU clock is 245.76 MHz
+       //      SYSCLK1   is 122.88 MHz
+       //      SYSCLK2   is  61.44 MHz
        //
        // EMIF settings, see SPRU621F, section 2.12 on "EMIF Registers"
        //
+       EGCR1 = 0xff7f;
+       EGCR2 = 0x0009;
        // EGCR1 = ...;   // (defaults)
        // EGCR2 = ...;   // (defaults)
        // CESCR1 = ...;   // (defaults)
@@ -478,42 +832,119 @@ void main (void) {
        // CE0_SC2 = ...;   // (defaults)
        //
        // CE1 selects the flash chip
-       CE1_1 = 0xff13;   // 16-bit async (and defaults)
+       //WORKED?// CE1_1 = 0xff13;   // 16-bit async (and defaults)
+       CE1_1 = 0x0922;
+       CE1_2 = 0x31f2;
        // CE1_2 = ...;   // (defaults)
        // CE1_SC1 = ...;   // (defaults)
        // CE1_SC2 = ...;   // (defaults)
        //
        // CE2 selects the SDRAM chips
-       CE2_1 = 0xff33;   // 32-bit SDRAM (and defaults)
+       //WORKS?// CE2_1 = 0xff33;   // 32-bit SDRAM (and defaults)
+       CE2_1 = 0xff37;
        //TEST// CE2_1 = 0xff13;   // 16-bit async (and defaults)
        // CE2_2 = ...;   // (defaults)
        // CE2_SC1 = ...;   // (defaults)
        // CE2_SC2 = ...;   // (defaults)
        // Possible: SDC1, SDC2, SDRC1, SDRC2, SDX1, SDX2
+       SDC1 = 0x6ffe;
+       SDC2 = 0x8712;
+       SDRC1 = 0xf5dc;
+       SDRC2 = 0xffff;
+       SDX1 = 0xb809;
+       CESCR1 = 0xfffc;
        //
        // CE3 selects the D-flipflops for keyboard and LCD
        CE3_1 = 0xff13;   // 16-bit async (and defaults)
+       //BT200ORIG// CE3_1 = 0x0220;
+       //BT200ORIG// CE3_2 = 0x0270;
        // CE3_2 = ...;   // (defaults)
        // CE3_SC1 = ...;   // (defaults)
        // CE3_SC2 = ...;   // (defaults)
        //
+       // Setup McBSP1 for linking to TLV320AIC20K
+       // Generate a CLKG at 12.288 MHz, and FS at 8 kHz
+       // following the procedure of spru592e section 3.5
+       //
+       DXR1_1 = 0x0000;
+       SPCR1_1 = 0x0000;
+       SPCR2_1 = 0x0000;
+       SRGR1_1 = REGVAL_SRGR1_FWID_1 | REGVAL_SRGR1_CLKGDIV_4;
+       SRGR2_1 = REGVAL_SRGR2_CLKSM | REGVAL_SRGR2_FSGM | REGVAL_SRGR2_FPER_1535;
+       PCR1 = /*TODO: (1 << REGBIT_PCR_IDLEEN) | */ (1 << REGBIT_PCR_FSXM) | /* TODO:CIRCUITED_TO_FSXM (1 << REGBIT_PCR_FSRM) | */ (1 << REGBIT_PCR_CLKXM) | (1 << REGBIT_PCR_CLKRM) /* TODO:WRONG? | (1 << REGBIT_PCR_CLKXP) | (1 << REGBIT_PCR_CLKRP) */;
+       SPCR1_1 = REGVAL_SPCR1_RRST_NOTRESET;
+       SPCR2_1 = REGVAL_SPCR2_XRST_NOTRESET | REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
+       //
+       // Setup I2C for communication with the TLV320AIC20K codec
+       // Prescale SYSCLK2 down from 61.44 MHz to 10.24 MHz; support a
+       // 100 kHz I2C bus by setting low/high period to 51 such periods.
+       //
+       I2CPSC = 5;
+       I2CCLKH = 51 - 5;
+       I2CCLKL = 51 - 5;
+       I2COAR = REGVAL_I2COAR;
+       I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
+       //
+       // Setup DMA channel 0 for playing from DSP to TLV320AIC2x
+       // Setup DMA channel 1 for recording from TLV320AIC2x to DSP
+       //
+       // Both channels have a block (their entire RAM buffer) comprising
+       // of 25 frames, which each are 64 samples of 16 bits in size.
+       // At 8 kHz sample rate, frames cause 125 interrupts per second;
+       // at 48 kHz this rises to 750 (per channel), still comfortable.
+       // The total buffer is 1600 samples of 16 bits long.  Each time a
+       // frame send finishes, an interrupt checks if there is another
+       // frame of 64 samples ready to go; if not, it will disable the
+       // DMA channel.  Hint routines service to restart DMA after that.
+       // Conversely, the DMA interrupt handlers can make top-calls to
+       // indicate that data is ready for reading or that space is
+       // available for writing.
+       // The settings below prepare DMA for continuous playing and
+       // recording, but with the setup disabled until hinted.
+       //
+       DMAGCR = REGVAL_DMAGCR_FREE;
+       DMAGTCR = 0x00;         // No timeout support
+       DMACCR_0 = REGVAL_DMACCR_SRCAMODE_POSTINC | REGVAL_DMACCR_DSTAMODE_CONST | REGVAL_DMACCR_PRIO | REGVAL_DMACCR_SYNC_MCBSP1_TEV | REGVAL_DMACCR_REPEAT | REGVAL_DMACCR_AUTOINIT;
+       DMACCR_1 = REGVAL_DMACCR_SRCAMODE_CONST | REGVAL_DMACCR_DSTAMODE_POSTINC | REGVAL_DMACCR_PRIO | REGVAL_DMACCR_SYNC_MCBSP1_REV | REGVAL_DMACCR_REPEAT | REGVAL_DMACCR_AUTOINIT;
+       DMACICR_0 = REGVAL_DMACICR_FRAMEIE;
+       DMACICR_1 = REGVAL_DMACICR_FRAMEIE;
+       DMACSDP_0 = REGVAL_DMACSDP_SRC_DARAM0 | REGVAL_DMACSDP_DST_PERIPH | REGVAL_DMACSDP_DATATYPE_16BIT;
+       DMACSDP_1 = REGVAL_DMACSDP_SRC_PERIPH | REGVAL_DMACSDP_DST_DARAM1 | REGVAL_DMACSDP_DATATYPE_16BIT;
+       DMACSSAL_0 = ((uint16_t) samplebuf_play)   << 1;
+       DMACSSAU_0 = ((uint16_t) samplebuf_play)   >> 15;
+       DMACDSAL_0 = ((uint16_t) DXR1_1) <<  1;
+       DMACDSAU_0 = ((uint16_t) DXR1_1) >> 15;
+       DMACSSAL_1 = ((uint16_t) DRR1_1) <<  1;
+       DMACSSAU_1 = ((uint16_t) DRR1_1) >> 15;
+       DMACDSAL_1 = ((uint32_t) samplebuf_record) << 1;
+       DMACDSAU_1 = ((uint32_t) samplebuf_record) >> 15;
+       DMACEN_0 = 64;           /* 64 elements (samples) per frame (continue-checks) */
+       DMACEN_1 = 64;
+       DMACFN_0 = (BUFSZ / 64); /* 25 frames (continue-checks) per block (buffer) */
+       DMACFN_1 = (BUFSZ / 64);
+       /* TODO? */
+       //
        // Further initiation follows
        //
        for (idx = 0; idx < APP_LEVEL_COUNT; idx++) {
                bt200_level_active [idx] = false;
        }
-       IODIR  |= (1 << 1);
-       IODATA |= (1 << 1);
+       IODIR  |= (1 << 7) | (1 << 1);
+       IODATA |= (1 << 7) | (1 << 1);
+       asm (" bclr xf");  // Switch off MESSAGE LED
 { uint16_t ctr = 250; while (ctr > 0) { ctr--; } }     
        bottom_critical_region_begin (); // _disable_interrupts ();
        IER0 = IER1 = 0x0000;
        tic55x_setup_timers ();
        tic55x_setup_interrupts ();
        ht162x_setup_lcd ();
+       tlv320aic2x_setup_sound ();
        ksz8842_setup_network ();
        // Enable INT0..INT3
-       IER0 |= 0x080c;
-       IER1 |= 0x0001;
+       //TODO:TEST// IER0 |= 0x0a0c;
+       //TODO:TEST// IER1 |= 0x0005;
+       IER0 |= (1 << REGBIT_IER0_DMAC1) | (1 << REGBIT_IER0_INT0) | (1 << REGBIT_IER0_TINT0); // 0x0214;
+       IER1 |= (1 << REGBIT_IER1_DMAC0); // 0x0004;
        PCR0 = (1 << REGBIT_PCR_XIOEN) | (1 << REGBIT_PCR_RIOEN);
 
 #if 0
@@ -524,10 +955,10 @@ while (true) {
 uint32_t ctr;
 ht162x_putchar (14 - idx, (dig < 10)? (dig + '0'): (dig + 'A' - 11));
 ht162x_audiolevel ((bar < 8)? (bar << 5): ((14-bar) << 5));
-bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+// bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
 ht162x_dispdata_notify (14 - idx, 14 - idx);
 ht162x_dispdata_notify (15, 15);
-bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+// bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
 idx = (idx + 1) % 12;
 dig = (dig + 1) % 38;
 bar = (bar + 1) % 14;
@@ -538,6 +969,7 @@ ctr = 650000; while (ctr>0) ctr--;
 
        //TODO// IER0 = 0xdefc;
        //TODO// IER1 = 0x00ff;
+/* TODO: Iterate over flash partitions that can boot, running each in turn: */
        top_main ();
 }
 
index e4380ef..bd1b778 100644 (file)
@@ -1,4 +1,21 @@
-/* tic55x interrupt handling */
+/* tic55x interrupt handling
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 
 #include <stdint.h>
index 422f643..69cea9e 100644 (file)
@@ -1,4 +1,22 @@
-               ; Create a subsection with interrupt service routine vectors
+; Create a subsection with interrupt service routine vectors
+;
+; This file is part of 0cpm Firmerware.
+;
+; 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+;
+; 0cpm Firmerware is free software: you can redistribute it and/or
+; modify it under the terms of the GNU General Public License as
+; published by the Free Software Foundation, version 3.
+;
+; 0cpm Firmerware is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+
+
                .sect   ".isrmap"
 
                .align  256
@@ -11,6 +29,8 @@
                .ref    _tic55x_no_isr
                .ref    _tic55x_tint0_isr
                .ref    _tic55x_int0_isr
+               .ref    _tic55x_dmac0_isr
+               .ref    _tic55x_dmac1_isr
 
 _tic55x_bootld .set    0xff8000
 
@@ -24,7 +44,7 @@ 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
+dmac1          .ivec   _tic55x_dmac1_isr
 dspint         .ivec   _tic55x_no_isr
 int3           .ivec   _tic55x_no_isr
 uart           .ivec   _tic55x_no_isr
@@ -33,7 +53,7 @@ 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
+dmac0          .ivec   _tic55x_dmac0_isr
                .ivec   _tic55x_no_isr
 dmac2          .ivec   _tic55x_no_isr
 dmac3          .ivec   _tic55x_no_isr
index e545a12..c394fb7 100644 (file)
@@ -1,6 +1,24 @@
 /* General timer management.
  *
- * The tic55x has multiple 64-bit timers, we'll use timer0 and timer1.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* 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:
@@ -75,6 +93,7 @@ timing_t bottom_timer_set (timing_t tim) {
        /* Juggle timing values to return the current setting */
        previous = current_timer;
        current_timer = tim;
+again:
        /* Setup counter and period registers for timer0 */
        GPTCNT3_0 = GPTCNT3_1; // Read CNT3, copy CNT4 to shadow
        GPTCNT4_0 = GPTCNT4_1; // Load CNT4 from shadow copy
@@ -87,10 +106,14 @@ timing_t bottom_timer_set (timing_t tim) {
        cnt2 = GPTCNT2_0;
        intval = tim - ((GPTCNT2_0 << 16) | GPTCNT1_0);
        if ((intval == 0) || (intval >> 31)) {
+               timing_t oldtimer = tim;
                // Invoke handler right now, do not run timer0
-               top_timer_expiration (tim);
-               current_timer = 0;
-               return previous;
+               tim = top_timer_expiration (oldtimer);
+               if (tim != oldtimer) {
+                       goto again; //TODO:TEST//
+               }
+               //TODO:OLD// current_timer = 0;
+               //TODO:OLD// return previous;
        }
        /* Finally, enable timer1 so it starts counting time */
        GPTGCTL1_0 |= REGVAL_GCTL_TIM12RS | REGVAL_GCTL_TIM34RS;
@@ -102,8 +125,12 @@ timing_t bottom_timer_set (timing_t tim) {
 interrupt void tic55x_tint0_isr (void) {
        extern volatile bool tic55x_top_has_been_interrupted;
        timing_t now = bottom_time ();
+       timing_t newsetting;
        current_timer = 0;
-       top_timer_expiration (now);
+       newsetting = top_timer_expiration (now);
+       if (now != newsetting) {
+               bottom_timer_set (now);
+       }
        tic55x_top_has_been_interrupted = true;
 }
 
@@ -116,9 +143,9 @@ void tic55x_setup_timers (void) {
        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);
+       GPTPRD4_1 = (uint16_t) (((uint32_t) SYSCLK1_TO_MS_DIVIDER-1) >> 16);
        GPTPRD3_0 =
-       GPTPRD3_1 = (uint16_t) ((SYSCLK1_TO_MS_DIVIDER-1) & 0xffff);
+       GPTPRD3_1 = (uint16_t) (((uint32_t) SYSCLK1_TO_MS_DIVIDER-1) & 0xffff);
        /* Let the upper half of timer1 count with a 2^32 period */
        GPTPRD2_1 =
        GPTPRD1_1 = 0xffff;
index 96f958b..08a0265 100644 (file)
@@ -1,5 +1,23 @@
 /* TLV320AIC20/21/24/25/20K/24K codec driver
  *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
  * The name "codec" is generally used for sound I/O chips that take a
  * realtime stream of samples and map send them to speakers; and that
  * do the opposite for microphone input.
  */
 
 
-/* Setup the sound channel to use: SOUND_NONE, _HANDSET, _HEADSET,
- * _SPEAKER and _LINE.  When set to SOUND_NONE, the chip is in setup
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <config.h>
+#include <0cpm/snd.h>
+
+
+/* The code below distinguishes the two directions of using the
+ * TLV320AIC2x codec as play and record:
+ *  - Play   translates from the digital domain to domain
+ *  - Record translates from the sound domain to the digital
+ *
+ * A buffer exists for each direction, and the host facilities
+ * (interrupts, DMA) are exploited to move data as efficiently
+ * as possible.
+ *
+ * Communincation normally does not wrap around the boundaries
+ * of the buffer.  That is, DMA will end a block at the end of
+ * the buffer, just to start over right away.  Similarly, the
+ * communication with the top is in terms of bytes left but
+ * never more than to the end of the buffers.  The top has to
+ * adapt to partial deliveries anyway, it is aware of that.
+ */
+
+
+/******** "Local" function definitions ********/
+
+
+uint8_t tlv320aic2x_getreg (uint8_t channel, uint8_t reg);
+void tlv320aic2x_setreg (uint8_t channel, uint8_t reg, uint8_t val);
+void tlv320aic2x_set_samplerate (uint32_t samplerate);
+void dmahint_play   (void);
+void dmahint_record (void);
+
+
+/******** Global variables ********/
+
+
+/* A stored version of the current volume, defaulting halfway */
+static uint8_t volume [2];
+
+
+/* Read and write buffers, with counters of read-ahead */
+
+#define BUFSZ (64*4)
+
+volatile uint16_t samplebuf_play   [BUFSZ];
+volatile uint16_t samplebuf_record [BUFSZ];
+
+volatile uint16_t available_play   = 0;
+volatile uint16_t available_record = 0;
+
+volatile uint16_t threshold_play   = 64;
+volatile uint16_t threshold_record = 64;
+
+static uint16_t nextwrite_play   = 0;
+static uint16_t nextwrite_record = 0;
+
+static uint16_t nextread_play    = 0;
+static uint16_t nextread_record  = 0;
+
+
+/******** Calls to change sound channels ********/
+
+
+/* Setup the sound channel to use: SOUNDDEV_NONE, _HANDSET, _HEADSET,
+ * _SPEAKER and _LINE.  When set to SOUNDDEV_NONE, the chip is in setup
  * in configuration programming mode; in any other modes, it is setup
  * in continuous data transfer mode.
  */
-void bottom_soundchannel (soundchannel_t sch) {
-       //TODO//
+void bottom_soundchannel_device (uint8_t chan, sounddev_t dev) {
+       if (dev != SOUNDDEV_NONE) {
+               tlv320aic2x_setreg (chan, 3, 0x00 | 0x01); /* power up */
+       }
+       switch (dev) {
+       case SOUNDDEV_NONE:
+               // Microphone input could act as a random seed
+               // (such material would be hashed to aid privacy)
+               // (but for now just powerdown the codec)
+               tlv320aic2x_setreg (chan, 6, 0x00 | 0x04);
+               tlv320aic2x_setreg (chan, 6, 0x80 | 0x00);
+               tlv320aic2x_setreg (chan, 3, 0x00 | 0x31); /* power down */
+               break;
+       case SOUNDDEV_HANDSET:
+               tlv320aic2x_setreg (chan, 6, 0x00 | 0x02);
+               tlv320aic2x_setreg (chan, 6, 0x80 | 0x02);
+               break;
+       case SOUNDDEV_HEADSET:
+               tlv320aic2x_setreg (chan, 6, 0x00 | 0x01);
+               tlv320aic2x_setreg (chan, 6, 0x80 | 0x01);
+               break;
+       case SOUNDDEV_SPEAKER:
+               tlv320aic2x_setreg (chan, 6, 0x00 | 0x04);
+               tlv320aic2x_setreg (chan, 6, 0x80 | 0x08);
+               break;
+       case SOUNDDEV_LINE:
+               tlv320aic2x_setreg (chan, 6, 0x00 | 0x08);
+               tlv320aic2x_setreg (chan, 6, 0x80 | 0x04);
+               break;
+       default:
+               break;
+       }
+}
+
+/* Retrieve the current volume */
+uint8_t bottom_soundchannel_getvolume (uint8_t chan) {
+       return volume [chan];
+}
+
+/* Set the current volume, but stay aware of wrap-around and beyond-range
+ * attempts.
+ */
+void bottom_soundchannel_setvolume (uint8_t chan, uint8_t vol) {
+       if (vol >= 200) {
+               /* wrap-around due to decrement */
+               vol = 0;
+       } else if (vol > 31) {
+               /* out-of-range due to increment (top does not know range) */
+               vol = 31;
+       } else {
+               /* regular value: literal copy or proper increment/decrement */
+       }
+       volume [chan] = vol;
+       tlv320aic2x_setreg (chan, 5, (0x40 | 31) - vol);
 }
 
+
+/******** Interrupt and DMA handling to indicate that sound can be inserted ********/
+
+
+//TODO:IRQHANDLER:CALLS// uint16_t top_codec_can_play   (uint8_t chan, uint16_t samples);
+//TODO:IRQHANDLER:CALLS// uint16_t top_codec_can_record (uint8_t chan, uint16_t samples);
+
+
+/******** Calls to play or record through a codec ********/
+
+
+int16_t codec_decode (codec_t codec, uint8_t *in, uint16_t inlen, uint16_t *out, uint16_t outlen);
+int16_t codec_encode (codec_t codec, uint16_t *in, uint16_t inlen, uint8_t *out, uint16_t outlen);
+void tlv320aic2x_set_samplerate (uint32_t samplerate);
+
+
+void bottom_codec_play_samplerate   (uint8_t chan, uint32_t samplerate) {
+       tlv320aic2x_set_samplerate (samplerate);
+}
+
+void bottom_codec_record_samplerate (uint8_t chan, uint32_t samplerate) {
+       // No setting to make: documentation says to call both with the same values
+       // bottom_codec_play_samplerate (chan, samplerate);
+       dmahint_record ();
+}
+
+int16_t bottom_codec_play   (uint8_t chan, codec_t codec, uint8_t *coded_samples, uint16_t coded_bytes, uint16_t samples) {
+       int16_t retval;
+       retval = codec_decode (codec,
+                               coded_samples, coded_bytes,
+                               (uint16_t *) (samplebuf_play + nextwrite_play), samples);
+       nextwrite_play += samples;
+       available_play += samples;
+       if (retval < 0) {
+               nextwrite_play += retval;
+               available_play += retval;
+       }
+       if (nextwrite_play >= BUFSZ) {
+               nextwrite_play -= BUFSZ;
+       }
+       dmahint_play ();
+       return retval;
+}
+
+int16_t bottom_codec_record (uint8_t chan, codec_t codec, uint8_t *coded_samples, uint16_t coded_bytes, uint16_t samples) {
+       int16_t retval;
+       retval = codec_encode (codec,
+                               (uint16_t *) (samplebuf_play + nextread_play), samples,
+                               coded_samples, coded_bytes);
+       nextread_record += samples;
+       available_record -= samples;
+       if (retval < 0) {
+               nextread_record += retval;
+               available_record -= retval;
+       }
+       dmahint_record ();
+       return retval;
+}
+
+void bottom_codec_play_skip (codec_t codec, uint16_t samples) {
+       uint16_t ctr;
+       //TODO: Better fill up with previous sample
+       if (available_play + samples > BUFSZ) {
+               samples = BUFSZ - available_play;
+       }
+       ctr = samples;
+       while (ctr-- > 0) {
+               samplebuf_play [nextwrite_play++] = 0x0000;
+               if (nextwrite_play >= BUFSZ) {
+                       nextwrite_play -= BUFSZ;
+               }
+       }
+       available_play += samples;
+       dmahint_play ();
+}
+
+
+/******** Initialisation of this module ********/
+
+
 /* Setup the communication with the codec, initialise the chip
  */
-void tls320aic2x_setup_sound (void) {
-       // TODO: Setup codec communications
-       bottom_soundchannel (SOUND_NONE);
+void tlv320aic2x_setup_sound (void) {
+       uint8_t chan;
+       // Setup the various registers in the TLV320AIC2x
+       for (chan = 0; chan < 2; chan++) {
+               tlv320aic2x_setreg (chan, 1,        0x49);      /* Continuous 16-bit, 2.35V bias */
+               tlv320aic2x_setreg (chan, 2,        0xa0);      /* Turbo mode */
+               /* Setup to SOUNDDEV_NONE below will power down the device */
+               tlv320aic2x_setreg (chan, 3, 0x40 | 0x20);      /* Arrange mute with volume 0 */
+               /* Ignore register 3C */
+               tlv320aic2x_setreg (chan, 3, 0xc0 | 0x00);      /* Switch off LCD DAC */
+               /* Bypass MNP setup, it is phone-speficic */
+               tlv320aic2x_setreg (chan, 5, 0x00 | 0x20);      /* ADC gain 27 dB -- ok? */
+               bottom_soundchannel_setvolume (chan, 16);       /* DAC gain -24 dB initially */
+               tlv320aic2x_setreg (chan, 5, 0x80 | 0x00);      /* No sidetones */
+               tlv320aic2x_setreg (chan, 5, 0xc0 | 0x30);      /* SPKR gain +3 dB -- ok? */
+               bottom_soundchannel_device (chan, SOUNDDEV_NONE);/* No input/output, powerdown */
+       }
 }
index dd8778d..10978e9 100644 (file)
@@ -1,6 +1,25 @@
 /* LED simulation support -- print them in tabbed columns
  *
- * Descriptions below are all restricted to 7 chars or less, so they
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+
+/* 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 <stdarg.h>
 
 #include <config.h>
 
 #include <0cpm/led.h>
+#include <0cpm/cons.h>
 
 
 char *led_colours_2 [] = { "off", "green" };
@@ -81,11 +102,11 @@ void bottom_led_set (led_idx_t lednum, led_colour_t col) {
        static headctr = 0;
        if (headctr++ % 20 == 0) {
                for (i = 0; i < LED_IDX_COUNT; i++) {
-                       printf ("\t%s", num2descr [i].name);
+                       bottom_printf ("\t%s", num2descr [i].name);
                }
-               printf ("\n");
+               bottom_printf ("\n");
        }
-       printf ("%3d.%03d", tv.tv_sec, tv.tv_usec / 1000);
+       bottom_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++) {
@@ -103,7 +124,7 @@ void bottom_led_set (led_idx_t lednum, led_colour_t col) {
                } else {
                        colnm = "UNSET";
                }
-               printf ("\t%s", colnm);
+               bottom_printf ("\t%s", colnm);
        }
-       printf ("\n");
+       bottom_printf ("\n");
 }
index 9a18e7f..d087978 100644 (file)
@@ -1,43 +1,58 @@
 /* tuntest.c -- Tunnel-based testing of the network code.
  *
- * From: Rick van Rein <rick@openfortress.nl>
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
 #include <stdlib.h>
-#include <stdio.h>
+// #include <stdio.h>
 #include <stdint.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <string.h>
 #include <fcntl.h>
-#include <errno.h>
+// #include <errno.h>
 
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <sys/uio.h>
+// #include <sys/types.h>
+// #include <sys/ioctl.h>
+// #include <sys/socket.h>
+// #include <sys/select.h>
+// #include <sys/time.h>
+// #include <sys/uio.h>
 
-#include <netinet/ip.h>
-#include <netinet/ip6.h>
-#include <netinet/udp.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/icmp6.h>
+// #include <netinet/ip.h>
+// #include <netinet/ip6.h>
+// #include <netinet/udp.h>
+// #include <netinet/ip_icmp.h>
+// #include <netinet/icmp6.h>
 
-#include <linux/if.h>
-#include <linux/if_tun.h>
-#include <linux/if_ether.h>
+// #include <linux/if.h>
+// #include <linux/if_tun.h>
+// #include <linux/if_ether.h>
 
 #include <config.h>
 
 #include <0cpm/cpu.h>
 #include <0cpm/netfun.h>
 #include <0cpm/netdb.h>
-
 #include <0cpm/timer.h>
 #include <0cpm/led.h>
+#include <0cpm/netinet.h>
+#include <0cpm/cons.h>
 
 
 int tunsox = -1;
@@ -54,52 +69,52 @@ bool sleepy = false;
  */
 
 uint8_t *net_arp_reply (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       printf ("Received: ARP Reply\n");
+       bottom_printf ("Received: ARP Reply\n");
        return NULL;
 }
 
 uint8_t *net_arp_query (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       printf ("Received: ARP Query\n");
+       bottom_printf ("Received: ARP Query\n");
        return NULL;
 }
 
 uint8_t *net_rtp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       printf ("Received: RTP\n");
+       bottom_printf ("Received: RTP\n");
        return NULL;
 }
 
 uint8_t *net_rtcp (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       printf ("Received: RTCP\n");
+       bottom_printf ("Received: RTCP\n");
        return NULL;
 }
 
 uint8_t *net_sip (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       printf ("Received: SIP\n");
+       bottom_printf ("Received: SIP\n");
        return NULL;
 }
 
 uint8_t *net_mdns_resp_error (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       //TODO// printf ("Received: mDNS error response\n");
+       //TODO// bottom_printf ("Received: mDNS error response\n");
        return NULL;
 }
 
 uint8_t *net_mdns_resp_dyn (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       //TODO// printf ("Received: mDNS dynamic response\n");
+       //TODO// bottom_printf ("Received: mDNS dynamic response\n");
        return NULL;
 }
 
 uint8_t *net_mdns_resp_std (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       //TODO// printf ("Received: mDNS standard response\n");
+       //TODO// bottom_printf ("Received: mDNS standard response\n");
        return NULL;
 }
 
 uint8_t *net_mdns_query_error (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       //TODO// printf ("Received: mDNS error query\n");
+       //TODO// bottom_printf ("Received: mDNS error query\n");
        return NULL;
 }
 
 uint8_t *net_mdns_query_ok (uint8_t *pkt, uint32_t pktlen, intptr_t *mem) {
-       //TODO// printf ("Received: mDNS ok query\n");
+       //TODO// bottom_printf ("Received: mDNS ok query\n");
        return NULL;
 }
 
@@ -123,7 +138,7 @@ timing_t bottom_time (void) {
        struct timeval now;
        timing_t retval;
        if (gettimeofday (&now, NULL) != 0) {
-               fprintf (stderr, "Failed to get clock time: %s\n", strerror (errno));
+               bottom_printf ("Failed to get clock time: %s\n", strerror (errno));
                return 0;
        }
        retval = now.tv_sec * 1000 + (now.tv_usec / 1000);
@@ -181,7 +196,7 @@ void bottom_sleep_commit (sleep_depth_t depth) {
                top_timer_expiration (exptm);
                sleepy = false;
        } else {
-               fprintf (stderr, "select() returned an error: %s\n", strerror (errno));
+               bottom_printf ("select() returned an error: %s\n", strerror (errno));
                sleep (1);
        }
 }
@@ -195,7 +210,7 @@ bool bottom_network_send (uint8_t *buf, uint16_t buflen) {
                if (errno == EAGAIN) {
                        return false;
                } else {
-                       fprintf (stderr, "Ignoring error after write to tunnel: %s\n", strerror (errno));
+                       bottom_printf ("Ignoring error after write to tunnel: %s\n", strerror (errno));
                }
        }
        return true;
@@ -208,7 +223,7 @@ bool bottom_network_recv (uint8_t *buf, uint16_t *buflen) {
                if (errno == EAGAIN) {
                        return false;
                } else {
-                       fprintf (stderr, "Ignoring error after read from tunnel: %s\n", strerror (errno));
+                       bottom_printf ("Ignoring error after read from tunnel: %s\n", strerror (errno));
                }
                *buflen = 0;
        } else if (rsz > sizeof (struct tun_pi)) {
@@ -249,7 +264,7 @@ int process_packets (int secs) {
 #if 0
                        int i;
                        for (i=0; i<28; i++) {
-                               printf ("  M[%d]=0x%08x%s", i, mem [i],
+                               bottom_printf ("  M[%d]=0x%08x%s", i, mem [i],
                                                ((i+1)%4 == 0)? "\n": "");
                        }
 #endif
@@ -317,14 +332,14 @@ int main (int argc, char *argv []) {
        init ();
        int tunsox = setup_tunnel ();
        if (tunsox == -1) {
-               fprintf (stderr, "Failed to setup tunnel\n");
+               bottom_printf ("Failed to setup tunnel\n");
                exit (1);
        }
        system ("/sbin/ifconfig test0cpm up");
        system ("/sbin/ifconfig test0cpm");
        sleep (10);
        top_main ();
-       fprintf (stderr, "top_main() returned -- which MUST NOT happen!\n");
+       bottom_printf (stderr, "top_main() returned -- which MUST NOT happen!\n");
        close (tunsox);
        exit (1);
 }
index 04e24d4..72769d8 100644 (file)
@@ -51,6 +51,8 @@ config MAINFUNCTION_SIP_ALARMCLOCK
 
 config MAINFUNCTION_BOOTLOADER
        bool "Bootloader"
+       select FUNCTION_NETCONSOLE
+       select FUNCTION_FIRMWARE_UPGRADES
        help
          Some phones have less RAM than Flash on board.  On such phones,
          stability improves with the installation of a small bootloader
@@ -63,15 +65,16 @@ config MAINFUNCTION_BOOTLOADER
 
          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.
+         automation, ...TODO...
 
-         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.
+         The bootloader does not run over IPv6 or even IPv4; it is only
+         routed locally because it runs as a TFTP server directly on top
+         of 802.2 Ethernet (LLC type 1).  You will need a special TFTP
+         client to be able to access the bootloader.
+
+         Note that the bootloader code itself can also be replaced by
+         the bootloader.  Be very careful when doing that, as there
+         will be no warning for quite a few mistakes you could make.
 
 endchoice
 
@@ -82,9 +85,9 @@ config FUNCTION_SOUND_PLAYER
          computers on the LAN to send sound to the phone to have it played.
          This is only possible on an IPv6-enabled LAN.
 
-config FUNCTION_DEVEL_NETCONSOLE
+config FUNCTION_NETCONSOLE
        bool "LAN-based console"
-       default y if DEVEL=y 
+       default y if DEVEL=n
        help
          Direct console traffic for the main application to the network.
 
@@ -104,13 +107,13 @@ config FUNCTION_DEVEL_NETCONSOLE
 
 config FUNCTION_FIRMWARE_UPGRADES
        bool "Support firmware upgrades"
-       depends on MAINFUNCTION_SIP_PHONE
-       default n
+       default y if MAINFUNCTION_BOOTLOADER=y
        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.
+         TODO: Also use TFTP over LLC1?
 
          If the upgrade fails, the phone will need to be upgraded
          through the bootloader, if it has one.
index 22c8340..8606a94 100644 (file)
@@ -29,7 +29,7 @@ config MAINFUNCTION_DEVEL_KEYBOARD
 config MAINFUNCTION_DEVEL_NETWORK
        bool "Test network"
        depends on DEVEL
-       select FUNCTION_DEVEL_NETCONSOLE
+       select FUNCTION_NETCONSOLE
        help
          This test runs a networked console.  The test will print information
          about incoming network packets and ignore traffic sent to the device.
index 8fe3c97..3083035 100644 (file)
@@ -3,11 +3,17 @@
 #
 # 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_SIP_PHONE) += src/function/sip6phone/topmain.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
+# objs-top-$(CONFIG_MAINFUNCTION_BOOTLOADER) += src/function/bootload.o bin/top-kernel.o bin/top-simplenet.o function
+
+objs-top-$(CONFIG_MAINFUNCTION_BOOTLOADER) += src/function/bootloader.o src/net/llconly.o src/function/netconsole.o
+
+#TODO# Must replace llconly.o with "real" LLC support in src/net/*
+objs-top-$(CONFIG_FUNCTION_NETCONSOLE) += src/function/netconsole.o src/net/llconly.o
+
+objs-top-$(CONFIG_FUNCTION_FIRMWARE_UPGRADES) += src/function/bootloader.o
 
-objs-top-$(CONFIG_FUNCTION_DEVEL_NETCONSOLE) += src/function/netconsole.o
 
 #
 # Test targets, useful during reverse engineering and forward development
diff --git a/src/function/bootloader.c b/src/function/bootloader.c
new file mode 100644 (file)
index 0000000..deb4738
--- /dev/null
@@ -0,0 +1,197 @@
+/* bootloader.c -- Access to flash partitions
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This module can be linked in with various targets, to give
+ * them access to the flash memory, and support updates.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <config.h>
+
+#include <0cpm/cons.h>
+#include <0cpm/flash.h>
+
+
+/* Sanity check */
+
+#ifndef HAVE_FLASH_PARTITIONS
+#error "This target does not define a flash partition table yet"
+#endif
+
+
+/* Global data */
+
+static struct flashpart *current = NULL;
+static uint16_t blocknum;
+static bool sending = false, receiving = false;
+
+
+/* Handle an incoming TFTP request (over LLC)
+ *
+ * This code is rather brutal -- it only does binary transfers,
+ * and it supports no options at all.
+ */
+
+void bootloader_datagram (uint8_t *pkt, uint16_t pktlen) {
+       void netreply_llc1 (uint8_t *pkt, uint16_t pktlen);
+       uint16_t cmd;
+       uint16_t pktlen2;
+       if (pktlen < 12 + 2 + 3 + 4) {
+               return;
+       }
+       pktlen2 = (pkt [12] << 8) | pkt [13];
+       if (pktlen < pktlen2 + 12 + 2) {
+               return;
+       }
+       cmd = (pkt [12 + 2 + 3 + 0] << 8) | pkt [12 + 2 + 3 + 1];
+       if ((cmd == 1) || (cmd == 2)) {         /* 1==RRQ, 2=WRQ, new setup */
+               pkt [pktlen - 1] = 0;
+               bottom_printf ("TFTP %s for %s\n",
+                       (cmd == 1)? "RRQ": "WRQ",
+                       pkt + 12 + 2 + 3 + 2);
+               current = (struct flashpart *) "TODO"; //TODO// current=flash_find_file(...), return if not found
+               sending   = (current != NULL) && (cmd == 1);
+               receiving = (current != NULL) && (cmd == 2);
+               pktlen = 12 + 2 + 3;
+               blocknum = 0;
+               if (sending) {
+                       goto sendblock;
+               }
+               if (receiving) {
+                       pkt [pktlen++] = 0x00;  // send ACK
+                       pkt [pktlen++] = 0x04;
+                       pkt [pktlen++] = 0x00;
+                       pkt [pktlen++] = 0x00;
+               }
+               netreply_llc1 (pkt, pktlen);
+       } else if (cmd == 3) {                  /* 3==DATA, store or burn */
+               if (!current) {
+                       bottom_printf ("TFTP DATA received without connection\n");
+               } else if (!receiving) {
+                       bottom_printf ("TFTP DATA received while not receiving\n");
+               } else if ((pktlen2 != 3 + 4 + 512) && (pktlen2 != 3 + 4 + 0)) {
+                       bottom_printf ("TFTP DATA is not a 512-byte block\n");
+               } else if (((pkt [12 + 2 + 3 + 2] << 8) | pkt [12 + 2 + 3 + 3]) != (blocknum + 1)) {
+                       bottom_printf ("TFTP DATA numbering out of sequence\n");
+               } else {
+                       blocknum++;
+                       /* Ignore, do not actually store the block anywhere */
+                       pkt [12 + 2 + 3 + 0] = 0x00;    // send ACK
+                       pkt [12 + 2 + 3 + 1] = 0x04;
+                       pkt [12 + 2 + 3 + 2] = blocknum >> 8;
+                       pkt [12 + 2 + 3 + 3] = blocknum & 0xff;
+                       netreply_llc1 (pkt, 12 + 2 + 3 + 4);
+               }
+       } else if (cmd == 4) {                  /* 4==ACK, send next if sending  */
+               if (!current) {
+                       bottom_printf ("TFTP ACK received without connection\n");
+               } else if (!sending) {
+                       bottom_printf ("TFTP ACK received while not sending\n");
+#if 0
+               } else if (pktlen != 12 + 2 + 3 + 4) {
+                       bottom_printf ("TFTP ACK is not of the proper legnth\n");
+#endif
+               } else if (((pkt [12 + 2 + 3 + 2] << 8) | pkt [12 + 2 + 3 + 3]) != blocknum) {
+                       bottom_printf ("TFTP ACK numbering out of sequence\n");
+               } else {
+sendblock:
+                       /* If more data is available, send it */
+                       blocknum++;
+                       pkt [12 + 2 + 3 + 0] = 0x00;    // send DATA
+                       pkt [12 + 2 + 3 + 1] = 0x03;
+                       pkt [12 + 2 + 3 + 2] = blocknum >> 8;
+                       pkt [12 + 2 + 3 + 3] = blocknum & 0xff;
+                       if (bottom_flash_read (blocknum - 1, pkt + 12 + 2 + 3 + 4)) {
+                               netreply_llc1 (pkt, 12 + 2 + 3 + 4 + 512);
+                       } else {
+                               netreply_llc1 (pkt, 12 + 2 + 3 + 4 + 0  );
+                       }
+               }
+       } else if (cmd == 5) {                  /* 5==ERR */
+               pkt [pktlen-1] = 0;
+               bottom_printf ("TFTP error %d received: %s\n", 
+                       (pkt [12 + 2 + 3 + 2] << 8) | pkt [12 + 2 + 3 + 3],
+                       pkt + 12 + 2 + 3 + 4);
+               /* no further error handling */
+       }
+       
+}
+
+
+
+/********** END OF LIBRARY FUNCTIONS ***** START OF MAIN PROGRAM **********/
+
+
+
+#ifdef CONFIG_MAINFUNCTION_BOOTLOADER
+
+/* Bootloader main program.
+ *
+ * Only included if the bootloader is compiled as the main target.
+ * If not, the bootloader is an optional add-on for the target.
+ */
+
+uint8_t pkt [700];
+void top_main (void) {
+       void nethandler_llconly (uint8_t *pkt, uint16_t pktlen);
+       bool active = false;
+       uint16_t pktlen;
+       bottom_critical_region_end ();
+       while (bottom_phone_is_offhook ()) {
+               if (!active) {
+                       bottom_printf ("TFTP bootloader starts on SAP 68\n");
+                       active = true;
+               }
+               pktlen = sizeof (pkt);
+               if (bottom_network_recv (pkt, &pktlen)) {
+                       nethandler_llconly (pkt, pktlen);
+               }
+       }
+       if (active) {
+               bottom_printf ("TFTP bootloader ends\n");
+               //TODO// Flush and close logging?
+       } else {
+               bottom_printf ("TFTP bootloader skipped -- reboot offhook to activate\n");
+       }
+}
+
+/* If this is the main program, various other functions are
+ * needed to keep the linker happy.
+ */
+void top_button_press (void) { ; }
+void top_button_release (void) { ; }
+void top_hook_update (void) { ; }
+void top_network_can_recv (void) { ; }
+void top_network_can_send (void) { ; }
+void top_network_offline (void) { ; }
+void top_network_online (void) { ; }
+void top_timer_expiration (void) { ; }
+void top_can_play (uint16_t samples) { ; }
+void top_can_record (uint16_t samples) { ; }
+
+#endif /* CONFIG_MAINFUNCTION_BOOTLOADER */
+
index c88cc04..0ee0b6d 100644 (file)
@@ -1,4 +1,22 @@
-/* bootloader -- TFTP on top of IP4LL to reveal flash contents */
+/* bootloader -- TFTP on top of IP4LL to reveal flash contents
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 
 #include <config.h>
 
index e69de29..8b9f308 100644 (file)
@@ -0,0 +1,142 @@
+/* echo.c -- Sound I/O test program
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This program will retrieve sound from the codec (sound chip), hold it for a bit,
+ * and send it back out.  When the phone is on-hook, sound communicates over the
+ * speakerphone function (if present).  When the phone is off-hook, sound
+ * communicates over the handset.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include <config.h>
+
+#include <0cpm/kbd.h>
+#include <0cpm/app.h>
+// #include <0cpm/cons.h>
+#include <0cpm/show.h>
+#include <0cpm/snd.h>
+#include <0cpm/led.h>
+
+
+volatile uint16_t tobeplayed   = 0;
+volatile uint16_t toberecorded = 0;
+
+
+void top_timer_expiration (timing_t timeout) {
+        /* Keep the linker happy */ ;
+}
+
+void top_hook_update (bool offhook) {
+        if (offhook) {
+               bottom_soundchannel_device (0, SOUNDDEV_SPEAKER);
+       } else {
+               bottom_soundchannel_device (0, SOUNDDEV_HANDSET);
+       }
+}
+
+void top_network_online (void) {
+        /* Keep the linker happy */ ;
+}
+
+void top_network_offline (void) {
+        /* Keep the linker happy */ ;
+}
+
+void top_network_can_send (void) {
+        /* Keep the linker happy */ ;
+}
+
+void top_network_can_recv (void) {
+        /* Keep the linker happy */ ;
+}
+
+void top_button_press (buttonclass_t bcl, buttoncode_t cde) {
+       /* Keep the linker happy */
+}
+
+void top_button_release (void) {
+       /* Keep the linker happy */
+}
+
+void top_can_play (uint16_t samples) {
+       tobeplayed = samples;
+}
+
+void top_can_record (uint16_t samples) {
+       toberecorded = samples;
+}
+
+
+uint8_t samples [10000];
+
+uint16_t playpos = 0;
+uint16_t recpos = 0;
+uint16_t sampled = 0;
+
+#define abs(x) (((x)>0)?(x):(-(x)))
+
+void top_main (void) {
+       bottom_critical_region_end ();
+       top_hook_update (bottom_phone_is_offhook ());
+       bottom_codec_play_samplerate (0, 8000);
+       bottom_codec_record_samplerate (0, 8000);
+       bottom_show_fixed_msg (APP_LEVEL_ZERO, FIXMSG_READY); // TODO: Not really necessary
+       while (true) {
+               if (toberecorded > 0) {
+                       int16_t rec = toberecorded;
+bottom_led_set (LED_IDX_HANDSET, 1);
+                       if (rec > 10000 - sampled) {
+                               rec = 10000 - sampled;
+                       }
+                       if (rec > 0) {
+                               // Codec implies that #samples and #bytes are the same
+                               rec -= abs (bottom_codec_record (0, CODEC_G711A, samples + recpos, rec, rec));
+                               recpos += rec;
+                               sampled += rec;
+                               bottom_critical_region_begin ();
+                               toberecorded -= rec;
+                               bottom_critical_region_end ();
+                       }
+               }
+               if (tobeplayed > 0) {
+                       int16_t ply = tobeplayed;
+bottom_led_set (LED_IDX_SPEAKERPHONE, 1);
+                       if (ply > sampled - 8000) {
+                               ply = sampled - 8000;
+                       }
+                       if (ply > 0) {
+                               ply -= abs (bottom_codec_play (0, CODEC_G711A, samples + playpos, ply, ply));
+                               playpos += ply;
+                               sampled -= ply;
+                               bottom_critical_region_begin ();
+                               tobeplayed -= ply;
+                               bottom_critical_region_end ();
+                       }
+               }
+       }
+}
+
index 81c0bd6..dbd112b 100644 (file)
@@ -1,4 +1,21 @@
-/* keys2display.c -- capture keys and show them on the display */
+/* keys2display.c -- capture keys and show them on the display
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 #include <stdint.h>
 #include <stdbool.h>
@@ -21,6 +38,30 @@ void top_hook_update (bool offhook) {
        /* Keep the linker happy */ ;
 }
 
+void top_network_online (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_offline (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_can_send (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_can_recv (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_can_play (uint16_t samples) {
+       /* Keep the linker happy */ ;
+}
+
+void top_can_record (uint16_t samples) {
+       /* Keep the linker happy */ ;
+}
+
 
 #define complete_top_main top_main
 
index f218b83..4755d3e 100644 (file)
@@ -1,6 +1,24 @@
 /* netconsole.c -- run a console over LLC over ethernet
  *
- * This test program includes a very small (and very selfish)
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This test program includes a very small (and very selfish)
  * network stack: It only does LLC2, and welcomes one LAN peer
  * at a time to connect to SAP 20 where a console is running.
  *
@@ -66,136 +84,21 @@ void top_network_can_recv (void) {
        /* Keep the linker happy */ ;
 }
 
-
-static bool llc_connected = false;
-static uint8_t peer_sap;
-static uint8_t peer_mac [6];
-static uint8_t llc_ua [6 + 6 + 2 + 3];
-static uint8_t llc_rr [6 + 6 + 2 + 4];
-static uint8_t llc_sent;
-static uint8_t llc_received;
-static uint8_t llc_input;
-
-
-/* Dummy LLC2 send routine, ignoring "cnx" as there is just one LLC2 connection.
- * Before sending, the routine will first establish whether the last send
- * was successful; if not, it will repeat that.  The return value is true if at
- * least the new send was done, relying on future calls to resend if need be.
- */
-uint8_t llc_pkt [100];
-uint16_t llc_pktlen;
-bool netsend_llc2 (struct llc2 *cnx, uint8_t *data, uint16_t datalen) {
-       bool newpkt;
-       if (datalen > 80) {
-               return false;
-       }
-       if (!llc_connected) {
-               return false;
-       }
-       newpkt = (llc_sent == llc_received);
-       if (newpkt) {
-               // Sending is complete, construct new packet as requested
-               memcpy (llc_pkt +  0, peer_mac, 6);
-               memcpy (llc_pkt +  6, "\x00\x0b\x82\x19\xa0\xf4", 6);
-               llc_pkt [12] = 0x00;
-               llc_pkt [13] = datalen + 4;
-               llc_pkt [14] = peer_sap;                // DSAP
-               llc_pkt [15] = 20;                      // SSAP
-               llc_pkt [16] = llc_sent << 1;           // N(S) = 0x00, information frame
-               llc_pkt [17] = llc_input << 1;          // N(R) = sent-up-to-here, low bit reset
-               memcpy (llc_pkt + 18, data, datalen);
-               llc_pktlen = 6 + 6 + 2 + 4 + datalen;
-               llc_sent++;
-               llc_sent &= 0x7f;
-       }
-       bottom_network_send (llc_pkt, llc_pktlen);
-       return newpkt;
+void top_can_play (void) {
+       /* Keep the linker happy */ ;
 }
 
-struct llc2 {
-       uint8_t dummy;
-};
-static struct llc2 llc2_dummy_handle;
-
-/* LLC2-only network packet handling */
-void selfish_llc2_handler (uint8_t *pkt, uint16_t pktlen) {
-       uint16_t typelen;
-       uint16_t cmd;
-       bool ack = false;
-       typelen = (pkt [12] << 8) | pkt [13];
-#if 0
-       if ((pktlen < 14) || (typelen < 46)) {
-               bottom_printf ("Unpadded packet length %d received\n", (unsigned int) pktlen);
-               return;
-       }
-#endif
-       if (typelen > 1500) {
-               bottom_printf ("Traffic is not LLC but protocol 0x%4x\n", (unsigned int) typelen);
-               return;
-       }
-       if ((typelen > 64) && (typelen != pktlen)) {
-               bottom_printf ("Illegal length %d received (pktlen = %d)\n", (unsigned int) typelen, (unsigned int) pktlen);
-               return;
-       }
-       if (pkt [14] != 20) {
-               bottom_printf ("Received LLC traffic for SAP %d instead of 20\n", (unsigned int) pkt [14]);
-               return;
-       }
-       if (llc_connected) {
-               if (memcmp (pkt + 6, peer_mac, 6) != 0) {
-                       // Peer MAC should be the constant while connected
-                       return;
-               }
-               if ((pkt [15] & 0xfe) != peer_sap) {
-                       // Peer SAP should be constant while connected
-                       return;
-               }
-       }
-       cmd = pkt [16];
-       if (typelen > 3) {
-               cmd |= pkt [17] << 8;
-       }
-       if (cmd == 0x007f) {                            // SABME (llc.connect)
-               memcpy (peer_mac, pkt + 6, 6);
-               peer_sap = pkt [15] & 0xfe;
-               llc_sent = llc_received = llc_input = 0x00;
-               llc_connected = true;
-               netcons_connect (&llc2_dummy_handle);
-               ack = true;
-       } else if (cmd == 0x0053) {                     // DISC  (llc.disconnect)
-               llc_connected = false;
-               netcons_close ();
-               ack = true;
-       } else if ((cmd & 0x0001) == 0x0000) {          // Data sent back (will be ignored)
-               memcpy (llc_rr +  0, peer_mac, 6);
-               memcpy (llc_rr +  6, "\x00\x0b\x82\x19\xa0\xf4", 6);
-                memcpy (llc_rr + 12, "\x00\x04\x00\x15", 4);
-               llc_rr [14] = peer_sap;
-                // memcpy (llc_rr + 12, "\x00\x04\x14\x00", 4);
-               // llc_rr [15] = peer_sap | 0x01;
-               llc_rr [16] = 0x01;                     // supervisory, RR
-               llc_rr [17] = (cmd + 2) & 0xfe;         // outgoing N(R) = incoming N(S) + 1
-               bottom_network_send (llc_rr, sizeof (llc_rr));
-       } else if ((cmd & 0x0007) == 0x0001) {          // Receiver ready / Receiver Reject
-               llc_received = (cmd >> 9);
-       } else {
-               bottom_printf ("Selfishly ignoring LLC traffic with cmd bytes 0x%2x%2x\n", (unsigned int) pkt [16], (unsigned int) pkt [17]);
-       }
-       if (ack) {
-               memcpy (llc_ua +  0, peer_mac, 6);
-               memcpy (llc_ua +  6, "\x00\x0b\x82\x19\xa0\xf4", 6);
-               memcpy (llc_ua + 12, "\x00\x03\x00\x15\x73", 5);
-               llc_ua [14] = peer_sap;
-               // Try sending; assume repeat will be caused by other/smarter side
-               bottom_network_send (llc_ua, sizeof (llc_ua));
-       }
+void top_can_record (void) {
+       /* Keep the linker happy */ ;
 }
 
 
+
 uint8_t netinput [1000];
 uint16_t netinputlen;
 
 void onlinetest_top_main (void) {
+       void nethandler_llconly (uint8_t *pkt, uint16_t pktlen);
        bottom_critical_region_end ();
        bottom_led_set (LED_IDX_BACKLIGHT, LED_STABLE_ON);
        while (true) {
@@ -205,15 +108,15 @@ void onlinetest_top_main (void) {
                        if (bottom_network_recv (netinput, &netinputlen)) {
                                if (memcmp (netinput, "\xff\xff\xff\xff\xff\xff", 6) == 0) {
                                        bottom_printf ("Broadcast from %2x:%2x:%2x:%2x:%2x:%2x\n",
-                                                       (unsigned int) netinput [ 6],
-                                                       (unsigned int) netinput [ 7],
-                                                       (unsigned int) netinput [ 8],
-                                                       (unsigned int) netinput [ 9],
-                                                       (unsigned int) netinput [10],
-                                                       (unsigned int) netinput [11]);
+                                                       (uint16_t) netinput [ 6],
+                                                       (uint16_t) netinput [ 7],
+                                                       (uint16_t) netinput [ 8],
+                                                       (uint16_t) netinput [ 9],
+                                                       (uint16_t) netinput [10],
+                                                       (uint16_t) netinput [11]);
                                } else {
                                        bottom_led_set (LED_IDX_BACKLIGHT, LED_STABLE_OFF);
-                                       selfish_llc2_handler (netinput, netinputlen);
+                                       nethandler_llconly (netinput, netinputlen);
                                }
                        }
                } else {
index 80d9971..d5ca7bc 100644 (file)
@@ -1,4 +1,22 @@
-/* switch2led.c -- simple test where hook contact drives message led */
+/* switch2led.c -- simple test where hook contact drives message led
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 
 #include <stdint.h>
 #include <stdbool.h>
 #include <0cpm/cpu.h>
 #include <0cpm/timer.h>
 #include <0cpm/led.h>
+#include <0cpm/kbd.h>
 
+#include <0cpm/app.h>          //TODO:EXTENSION-OF-MINIMAL-TEST//
+#include <0cpm/show.h>         //TODO:EXTENSION-OF-MINIMAL-TEST//
 
 #define complete_top_main top_main
 
 
-void top_timer_expiration (timing_t when) { ; }
+void top_timer_expiration (timing_t timeout) {
+       /* Keep the linker happy */ ;
+}
+
+void top_hook_update (bool offhook) {
+       /* Keep the linker happy */ ;
+}
+
+void top_button_press (buttonclass_t bcl, buttoncode_t cde) {
+       /* Keep the linker happy */ ;
+}
+
+void top_button_release (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_online (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_offline (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_can_send (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_can_recv (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_can_play (uint16_t samples) {
+       /* Keep the linker happy */ ;
+}
+
+void top_can_record (uint16_t samples) {
+       /* Keep the linker happy */ ;
+}
 
 
 void simpler_top_main (void) {
@@ -23,12 +82,12 @@ void simpler_top_main (void) {
                while (ctr > 0) {
                        ctr--;
                }
-               bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+               bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );       //TODO:EXTENSION-OF-MINIMAL-TEST//
                ctr = 65000;
                while (ctr > 0) {
                        ctr--;
                }
-               bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+               bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);       //TODO:EXTENSION-OF-MINIMAL-TEST//
        }
 }
 
@@ -37,8 +96,10 @@ void complete_top_main (void) {
        while (true) {
                if (bottom_phone_is_offhook ()) {
                        bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+                       bottom_show_fixed_msg (APP_LEVEL_BACKGROUNDED, FIXMSG_RINGING);
                } else {
                        bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+                       bottom_show_fixed_msg (APP_LEVEL_BACKGROUNDED, FIXMSG_READY);
                }
        }
 }
index 68bb311..3c9909b 100644 (file)
@@ -1,4 +1,22 @@
-/* timer2led.c -- simple test where a timer toggles a LED (T=1s, D=50%) */
+/* timer2led.c -- simple test where a timer toggles a LED (T=1s, D=50%)
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 
 #include <stdint.h>
 #include <stdbool.h>
@@ -9,6 +27,7 @@
 #include <0cpm/cpu.h>
 #include <0cpm/timer.h>
 #include <0cpm/led.h>
+#include <0cpm/kbd.h>
 
 
 volatile led_colour_t ledstate = LED_STABLE_ON;
@@ -18,6 +37,43 @@ volatile timing_t nextirq;
 #define snoozing_top_main top_main
 
 
+void top_hook_update (bool offhook) {
+       /* Keep the linker happy */ ;
+}
+
+void top_button_press (buttonclass_t bcl, buttoncode_t cde) {
+       /* Keep the linker happy */ ;
+}
+
+void top_button_release (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_online (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_offline (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_can_send (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_network_can_recv (void) {
+       /* Keep the linker happy */ ;
+}
+
+void top_can_play (uint16_t samples) {
+       /* Keep the linker happy */ ;
+}
+
+void top_can_record (uint16_t samples) {
+       /* Keep the linker happy */ ;
+}
+
+
 void doesitcount_top_main (void) {
        uint16_t ctr;
        timing_t lastcaught = bottom_time ();
index 6104392..418d982 100644 (file)
@@ -1,6 +1,24 @@
 /* Network console interface.
  *
- * This interface makes it possible to connect to the phone's console
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This interface makes it possible to connect to the phone's console
  * over LLC.  The advantage of LLC is that it works on a LAN only,
  * and does not require any support of protocols higher than Ethernet.
  * This makes it suitable to even debug things like IP leases.
@@ -32,7 +50,7 @@
  * The entire data and code portion depends on the function NETCONSOLE
  * being configured through "make menuconfig".
  */
-#ifdef CONFIG_FUNCTION_DEVEL_NETCONSOLE
+#ifdef CONFIG_FUNCTION_NETCONSOLE
 
 
 /******** BUFFER STATIC VARIABLES ********/
@@ -125,10 +143,10 @@ void bottom_console_vprintf (char *fmt, va_list argh) {
        char *fp = fmt;
        char *str;
        char ch;
-       unsigned long int intval;
+       uint32_t intval;
        while (*fp) {
                uint8_t minpos = 0;
-               bool longval = false;
+               bool val32bit = false;
                if (*fp != '%') {
                        cons_putchar (*fp++);
                } else {
@@ -139,7 +157,7 @@ void bottom_console_vprintf (char *fmt, va_list argh) {
                                fp--;
                                break;
                        case 'l':
-                               longval = true;
+                               val32bit = true;
                                goto moremeuk;
                        case '0':
                        case '1':
@@ -174,22 +192,22 @@ void bottom_console_vprintf (char *fmt, va_list argh) {
                                }
                                break;
                        case 'd':
-                               if (longval) {
-                                       intval =                     va_arg (argh, unsigned long int);
+                               if (val32bit) {
+                                       intval =            va_arg (argh, uint32_t);
                                } else {
-                                       intval = (unsigned long int) va_arg (argh, unsigned int);
+                                       intval = (uint32_t) va_arg (argh, uint16_t);
                                }
                                cons_putint (intval, 10, minpos);
                                break;
                        case 'p':
-                               intval = (unsigned long int) va_arg (argh, void *);
+                               intval = (uint32_t) va_arg (argh, void *);
                                cons_putint (intval, 16, (minpos > 8)? minpos: 8);
                                break;
                        case 'x':
-                               if (longval) {
-                                       intval =                     va_arg (argh, unsigned long int);
+                               if (val32bit) {
+                                       intval =            va_arg (argh, uint32_t);
                                } else {
-                                       intval = (unsigned long int) va_arg (argh, unsigned int);
+                                       intval = (uint32_t) va_arg (argh, uint16_t);
                                }
                                cons_putint (intval, 16, minpos);
                                break;
@@ -211,4 +229,4 @@ void bottom_console_printf (char *fmt, ...) {
 }
 
 
-#endif   /* CONFIG_FUNCTION_DEVEL_NETCONSOLE */
+#endif   /* CONFIG_FUNCTION_NETCONSOLE */
index 0eaea56..2fcbd82 100644 (file)
+/* SIP over IPv6 firmware phone
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <config.h>
+
+#include <0cpm/cpu.h>
+#include <0cpm/kbd.h>
+#include <0cpm/led.h>
+#include <0cpm/irq.h>  //TODO:ONLY-FOR-PATCHWORK-BELOW
+
+
+
+/* TODO: shared variables for debugging's sake */
+enum netcfgstate {
+       NCS_OFFLINE,    // Await top_network_online()
+       NCS_AUTOCONF,   // A few LAN autoconfiguration attempts
+       NCS_DHCPV6,     // A few LAN DHCPv6 attempts
+       NCS_DHCPV4,     // A few LAN DHCPv4 attempts
+       NCS_ARP,        // A few router-MAC address fishing attempts
+       NCS_6BED4,      // A few 6BED4 attempts over IPv4
+       NCS_ONLINE,     // Stable online performance
+       NCS_RENEW,      // Stable online, but renewing DHCPv6/v4
+       NCS_PANIC,      // Not able to bootstrap anything
+       NCS_HAVE_ALT = NCS_6BED4,
+};
+extern enum netcfgstate boot_state;
+static uint8_t nextround = 0x00;       // Local, only for test purposes
+
+
+void top_hook_update (bool offhook) {
+       /* Keep the linker happy */ ;
+}
+
+void top_can_play (uint16_t samples) {
+       /* Keep the linker happy */ ;
+}
+
+void top_can_record (uint16_t samples) {
+       /* Keep the linker happy */ ;
+}
+
+void top_button_press (buttonclass_t bcl, buttoncode_t cde) {
+       if (bcl != BUTCLS_DTMF) {
+               return;
+       }
+       switch (cde) {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+               nextround = cde - '0';
+               bottom_critical_region_begin ();
+               top_network_offline ();
+               bottom_critical_region_end ();
+               break;
+       default:
+               break;
+       }
+}
+
+void top_button_release (void) {
+       if (nextround != 0x00) {
+               bottom_critical_region_begin ();
+               top_network_online ();
+               boot_state = nextround; // Haven't switched to handler yet!
+               bottom_critical_region_end ();
+       }
+       nextround = 0x00;
+}
+
+
+extern priority_t cur_prio;
+
+
+
+/* TODO: bottom definitions shouldn't be copied in the top */
+extern volatile uint16_t IER0, IER1;
+asm ("_IER0 .set 0x0000");
+asm ("_IER1 .set 0x0045");
+#define REGBIT_IER0_TINT0       4
+#define REGBIT_IER0_DMAC1       9
+#define REGBIT_IER0_INT0       2
+#define REGBIT_IER1_TINT1       6
+#define REGBIT_IER1_DMAC0       2
 
+/* TODO: shared variables for debugging's sake */
+extern uint8_t          boot_retries;
+#include <0cpm/cpu.h>
+#include <0cpm/irq.h>
+#include <0cpm/timer.h>
+#include <0cpm/netdb.h>
+extern struct ip6binding ip6binding [IP6BINDING_COUNT];
+uint8_t bad;
+
+irqtimer_t disptimer;
+int nibblepos = 0;
+timing_t nextrot = 0;
+void show_info (irqtimer_t *tmr) {
+       int relpos;
+       //TODO:MANUAL_TIMER_AS_REAL_ONE_FAILS://
+#if 0
+       timing_t now = bottom_time ();
+       if (TIME_BEFORE (now, nextrot)) {
+               return;
+       }
+       nextrot += TIME_MSEC (1000);
+#endif
+bottom_keyboard_scan ();
+       if ((ip6binding [0].flags & (I6B_DEFEND_ME | I6B_EXPIRED)) == I6B_DEFEND_ME) {
+               for (relpos = 0; relpos < 12; relpos++) {
+                       int actpos = relpos + nibblepos;
+                       uint8_t ip6digit = 0x00;
+                       if ((actpos >= 12) && (actpos < 44)) {
+                               ip6digit = ip6binding [0].ip6addr [(actpos - 12) >> 1];
+                               if ((actpos & 0x01) == 0x00) {
+                                       ip6digit >>= 4;
+                               }
+                               ip6digit &= 0x0f;
+                               ip6digit += (ip6digit < 10)? '0': ('A'-10);
+                       }
+                       ht162x_putchar (14 - relpos, ip6digit, false);
+               }
+               nibblepos = (nibblepos + 1) % 44;
+       } else {
+               for (relpos=0; relpos<12; relpos++) {
+                       ht162x_putchar (14 - relpos, '-', false);
+               }
+               nibblepos = 0;
+       }
+       ht162x_dispdata_notify (3, 14);
+       irqtimer_restart (tmr, TIME_MSEC (1000));
+}
 
 /* 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) {
+#if 0
+bool have_ipv4 (void);
+bool have_ipv6 (void);
+#endif
+       uint8_t ipish [4] = { 0, 0, 0, 0 };
        // TODO: init ();
-       netdb_initialise ();
+bottom_led_set (LED_IDX_SPEAKERPHONE, 1);
+bottom_led_set (LED_IDX_BACKLIGHT, 1);
+       // netdb_initialise ();
        // TODO: cpu_add_closure (X);
        // TODO: cpu_add_closure (Y);
        // TODO: cpu_add_closure (Z);
+// IER0 &= ~(1 << REGBIT_IER0_INT0);
+// IER1 &= 0xffff; // ~(1 << REGBIT_IER1_DMAC0);
        bottom_critical_region_end ();
-       top_network_online ();  // TODO: Should be called from bottom!
+       // netcore_bootstrap_initiate ();
+bottom_led_set (LED_IDX_SPEAKERPHONE, 0);
+       irqtimer_start (&disptimer, TIME_MSEC (1000), show_info, CPU_PRIO_LOW);
        while (true) {
-               jobhopper ();
-               bottom_sleep_prepare ();
-               if (cur_prio == CPU_PRIO_ZERO) {
-                       bottom_sleep_commit (SLEEP_SNOOZE);
+#if 0
+               if (have_ipv6 ()) {
+                       bottom_show_ip6 (1, ip6binding [0].ip6addr);
+               } else {
+                       ipish [0] = (uint8_t) boot_state;
+                       ipish [1] = boot_retries;
+                       ipish [2] = bad;
+                       ipish [3] = have_ipv4 ()? 4: 0;
+                       bottom_show_ip4 (1, ipish);
                }
+#else
+               //TODO:TIMERED// show_info (&disptimer);
+#endif
+bottom_led_set (LED_IDX_BACKLIGHT, bottom_phone_is_offhook ()? 1: 0);
+
+               jobhopper ();
+bottom_led_set (LED_IDX_HANDSET, 1);
+               //TODO// bottom_sleep_prepare ();
+               //TODO// if (cur_prio == CPU_PRIO_ZERO) {
+                       //TODO// bottom_sleep_commit (SLEEP_SNOOZE);
+               //TODO// }
+#if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
+               //TODO:TIMERED// bottom_keyboard_scan ();
+#endif
        }
 }
 
index 20c793a..1f0a484 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Application drivers
  *
- * Application drivers
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index bd97f89..2a84f10 100644 (file)
@@ -1,24 +1,45 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* CPU drivers
  *
- * CPU drivers
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <stdarg.h>
+
+#include <config.h>
 
 #include <0cpm/cpu.h>
 #include <0cpm/irq.h>
+#include <0cpm/cons.h>
 
 
 /* Round-robin queues with interrupts and closures, ordered by priority.
  * To be fair, the elements pointed at have already been completed
  * and are awaiting roll-over or removal.
+ * TODO: Make the array contents volatile
  */
-irq_t     *irqs     [CPU_PRIO_COUNT];
-closure_t *closures [CPU_PRIO_COUNT];
+irq_t     *irqs     [CPU_PRIO_COUNT] = { NULL, NULL, NULL, NULL };
+closure_t *closures [CPU_PRIO_COUNT] = { NULL, NULL, NULL, NULL };
+#if CPU_PRIO_COUNT != 4
+//TODO// #  error "Update the number of NULL value initialisations above"
+#endif
 
 /* The current priority is an optimisation; it tells what the highest
  * active priority is, so as to avoid too much searching.  The priority
@@ -26,18 +47,28 @@ closure_t *closures [CPU_PRIO_COUNT];
  * as anything is scheduled, the value is increased to signal work is to
  * be done.
  */
-priority_t cur_prio = CPU_PRIO_ZERO;
+volatile priority_t cur_prio = CPU_PRIO_ZERO;
 
 
-/* Add an IRQ to the round-robin task queue to be scheduled */
+/* Add an IRQ to the round-robin task queue to be scheduled.
+ * This routine must always be called with interrupts inactive;
+ * either as part of an interrupt routine, or when called in the
+ * course of the main program, from within a critical region.
+ */
 void irq_fire (irq_t *irq) {
        priority_t p = irq->irq_priority;
+//TODO// if (irq->irq_next) return;
+       if (irqs [p]) {
+               irq->irq_next = irqs [p]->irq_next;
+               irqs [p]->irq_next = irq;
+       } else {
+               irq->irq_next = irq;
+       }
+       irqs [p] = irq; // Newly added becomes last in the queue
        if (p > cur_prio) {
                cur_prio = p;
        }
-       irq->irq_next = irqs [p]? irqs [p]: irq;
-       irqs [p] = irq;
-       irqs [p] = irqs [p]->irq_next;
+//TODO:TEST// ht162x_audiolevel (1 << 5);
 }
 
 
@@ -48,23 +79,44 @@ void irq_fire (irq_t *irq) {
  * be set to CPU_PRIO_ZERO.
  */
 void jobhopper (void) {
-       printf ("Jobhopper starts.\n");
+void ht162x_putchar (uint8_t idx, uint8_t ch, bool notify);
+       bottom_printf ("Jobhopper starts.\n");
+//TODO:TEST// ht162x_putchar (0, '0', true);
        while (cur_prio > CPU_PRIO_ZERO) {
+               closure_t *here;
+//TODO:TEST// ht162x_putchar (0, '1', true);
                while (irqs [cur_prio]) {
-                       irq_t *this;
-                       irqs [cur_prio] = irqs [cur_prio]->irq_next;
-                       while (this = irqs [cur_prio], this != NULL) {
-                               if (this != this->irq_next) {
-                                       irqs [cur_prio] = this->irq_next;
+//TODO:TEST// ht162x_putchar (0, '2', true);
+                       //TODO:JUSTREMOVE// irqs [cur_prio] = irqs [cur_prio]->irq_next;
+                       while (true) {
+                               irq_t *prev;
+                               irq_t *todo;
+                               bottom_critical_region_begin ();
+                               prev = irqs [cur_prio];
+                               if (prev == NULL) {
+                                       bottom_critical_region_end ();
+                                       break;
+                               }
+                               todo = prev->irq_next;
+                               if (prev != todo) {
+//TODO:TEST// ht162x_audiolevel (1 << 5);
+//TODO:TEST// ht162x_putchar (0, '3', true);
+                                       prev->irq_next = todo->irq_next;
                                } else {
+//TODO:TEST// ht162x_audiolevel (1 << 5);
+//TODO:TEST// ht162x_putchar (0, '4', true);
                                        irqs [cur_prio] = NULL;
                                }
-                               this->irq_next = NULL;
-                               printf ("Jobhopper calls interrupt handler.\n");
-                               (*this->irq_handler) (this);
+                               todo->irq_next = NULL;
+                               bottom_critical_region_end ();
+                               bottom_printf ("Jobhopper calls interrupt handler.\n");
+//TODO:TEST// ht162x_audiolevel (2 << 5);
+//TODO:NAAAHHH// if (this->irq_handler)
+                               (*todo->irq_handler) (todo);
+//TODO:TEST// ht162x_putchar (0, '5', true);
                        }
                }
-               closure_t *here = closures [cur_prio];
+               here = closures [cur_prio];
                if (here) {
                        closures [cur_prio] = here->cls_next;
                        here->cls_next = NULL;
@@ -72,16 +124,20 @@ void jobhopper (void) {
                        if (here) {
                                closure_t **last = &closures [cur_prio];
                                while (*last != NULL) {
+//TODO:TEST// ht162x_putchar (0, '6', true);
                                        last = &(*last)->cls_next;
                                }
-                               printf ("Jobhopper found closure -- TODO: call it!\n");
+//TODO:TEST// ht162x_putchar (0, '7', true);
+                               bottom_printf ("Jobhopper found closure -- TODO: call it!\n");
                                here->cls_next = NULL;
                                *last = here;
                        }
                } else {
+//TODO:TEST// ht162x_putchar (0, '8', true);
                        cur_prio--;
                }
        }
-       printf ("Jobhopper ends.\n");
+//TODO:TEST// ht162x_putchar (0, '9', true);
+       bottom_printf ("Jobhopper ends.\n");
 }
 
index f28229d..9d76d92 100644 (file)
@@ -1,15 +1,28 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* LED drivers
  *
- * LED drivers
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
-#include <config.h>
-
 #include <stdint.h>
 #include <stdbool.h>
 
+#include <config.h>
+
 #include <0cpm/cpu.h>
 #include <0cpm/irq.h>
 #include <0cpm/timer.h>
 
 
 /* Refer to the top handler state storage structures for LED information.
- * The size of the array is LED_IDX_COUNT as derived above.
+ * The size of the array is LED_IDX_COUNT as derived above.  The embedded
+ * timer is used to make the LED flash in its own pace.  The timer is
+ * started from the main program, and the corresponding interrupt is
+ * finished by the restarting routine for the timer.
+ * TODO: How to stop flashing while the IRQ is pending?
  */
 struct led_state {
        irqtimer_t      led_timer;
index 9dd479e..69e1816 100644 (file)
@@ -1,17 +1,41 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Network multiplexing for incoming traffic.
  *
- * Network multiplexing for incoming traffic.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+
+/* This is the kernel
+ * interface to the networking code; it mainly involves scheduling.
  */
 
 
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <stdarg.h>
+
+#include <config.h>
 
 #include <0cpm/cpu.h>
 #include <0cpm/irq.h>
+#include <0cpm/netinet.h>
 #include <0cpm/netfun.h>
+#include <0cpm/cons.h>
 
 
 /* TODO: Current return function from netinput
@@ -33,16 +57,12 @@ static bool can_recv = false;
 static void network_recv_handler (irq_t *irq);
 static void network_send_handler (irq_t *irq);
 
-static irq_t recv_irq = {
-       .irq_handler = network_recv_handler,
-       .irq_next = NULL,
-       .irq_priority = CPU_PRIO_UNKNOWN,
-};
-static irq_t send_irq = {
-       .irq_handler = network_send_handler,
-       .irq_next = NULL,
-       .irq_priority = CPU_PRIO_UNKNOWN,
-};
+/* The network receive handler is fired as soon as network
+ * packets arrive.  The network send handler is fired as soon
+ * as network packets have completed sending.
+ */
+static irq_t recv_irq = { network_recv_handler, NULL, CPU_PRIO_UNKNOWN };
+static irq_t send_irq = { network_send_handler, NULL, CPU_PRIO_UNKNOWN };
 
 
 
@@ -58,6 +78,7 @@ void top_network_can_recv (void) {
        if (!can_recv) {
                can_recv = true;
                irq_fire (&recv_irq);
+//ht162x_led_set (15, 1, true);        // shown as (101)
        }
 }
 
@@ -99,35 +120,57 @@ void top_network_online (void) {
 }
 
 /* As the processor now has time for it, process
- * the reception of network packets.
+ * the reception of network packets.  Where simple
+ * stimulus-response action is possible, do that.
  */
+packet_t myrbuf;//TODO:ELSEWHERE//
+packet_t mywbuf; // TODO: Allocate:ELSEWHERE
+intptr_t mymem [MEM_NETVAR_COUNT];//TODO:ELSEWHERE//
 static void network_recv_handler (irq_t *irq) {
-       bool go = can_recv;
+intptr_t netinput (uint8_t *pkt, uint16_t pktlen, intptr_t *mem);
+void ht162x_putchar (uint8_t idx, uint8_t ch, bool notify);
+       bool go;
+//TODO:TEST// ht162x_putchar (1, '0', true);
+       go = can_recv;
        can_recv = false;
        // TODO: rescheduling would be better than looping
        while (go) {
-               packet_t rbuf;
-               uint16_t rbuflen = sizeof (rbuf.data);
-               go = bottom_network_recv (rbuf.data, &rbuflen);
+               uint16_t rbuflen = sizeof (myrbuf.data);
+               retfn *rf;
+//TODO:TEST// ht162x_putchar (1, '1', true);
+               go = bottom_network_recv (myrbuf.data, &rbuflen);
                if (!go) {
-                       break;
+                       goto done;//TODO//break;
                }
-               printf ("Received a network packet\n");
-               intptr_t mem [MEM_NETVAR_COUNT];
-               bzero (mem, sizeof (mem));
-               retfn *rf = (retfn *) netinput (rbuf.data, rbuflen, mem);
+//TODO:TEST// ht162x_putchar (1, '2', true);
+               bottom_printf ("Received a network packet\n");
+               bzero (mymem, sizeof (mymem));
+               rf = (retfn *) netinput (myrbuf.data, rbuflen, mymem);
+//TODO:TEST// ht162x_putchar (1, '3', true);
                if (rf != NULL) {
-                       packet_t wbuf; // TODO: Allocate
-                       uint8_t *stop = (*rf) (wbuf.data, mem);
+                       uint8_t *stop = (*rf) (mywbuf.data, mymem);
+//TODO:TEST// ht162x_putchar (1, '4', true);
                        if (stop) {
-                               mem [MEM_ALL_DONE] = (intptr_t) stop;
-                               netcore_send_buffer (mem, wbuf.data);
+//TODO:TEST// ht162x_putchar (1, '5', true);
+                               mymem [MEM_ALL_DONE] = (intptr_t) stop;
+                               netcore_send_buffer (mymem, mywbuf.data);
+//TODO:TEST// ht162x_putchar (1, '6', true);
                        }
+//TODO:TEST// else ht162x_putchar (1, '7', true);
                }
        }
+done://TODO
        if (go) {
-               can_recv = true;  // TODO: Future IRQ trigger?
+//TODO:TEST// ht162x_putchar (1, '8', true);
+               bottom_critical_region_begin ();
+               if (!can_recv) {
+                       can_recv = true;
+if (irq)
+                       irq_fire (irq);
+               }
+               bottom_critical_region_end ();
        }
+//TODO:TEST// ht162x_putchar (1, '9', true);
 }
 
 
@@ -139,3 +182,4 @@ static void network_send_handler (irq_t *irq) {
        can_send = false;
        // TODO: Go over priority queues, bottom_network_send()
 }
+
index 4a50db0..5e05881 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Resource management.
  *
- * Resource management.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index fd85ac4..4f16204 100644 (file)
@@ -1,19 +1,75 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Timer drivers
  *
- * Timer drivers
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
-#include <config.h>
-
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <stdarg.h>
+
+#include <config.h>
 
 #include <0cpm/cpu.h>
 #include <0cpm/irq.h>
+#include <0cpm/led.h> //TODO// Just for testing
 #include <0cpm/timer.h>
+#include <0cpm/cons.h>
+
+
+
+/* Timers are deferred actions.  Some of those actions may be of a
+ * repetitive nature (at fixed intervals) and others may be oneshots.
+ *
+ * The actions triggered after the specified time has passed are
+ * invoked as an interrupt handler.  If continued actions are needed,
+ * including repeated activation, the interrupt handler should set it
+ * up before it exits.
+ *
+ * The bottom half only needs to support a single timer.  This top
+ * module administers a queue of timers, and will wait for the
+ * passing of the shortest time in the queue.  The queue therefore
+ * is ordered from the first timer to expire to the last.
+ *
+ * The bottom invokes top_timer_expiration() with the timing_t that
+ * triggered the timer expiration.  The function should return the
+ * new setting for the bottom timer, if any, or otherwise simply
+ * the same value as was handed to it upon invocation.  The bottom
+ * will then setup the hardware timer accordingly.  It is the
+ * bottom's responsibility to avoid setting a timing_t value that
+ * has actually expired; if that was allowed to happen, the whole
+ * system might get stuck.  The top ensures that invocations of
+ * top_timer_expiration() fire an interrupt for all expired timers,
+ * but do nothing if no timers had expired.  Furthermore, there
+ * is a facility to temporarily disable timer expirations to lead
+ * to interrupts being triggered.
+ *
+ * The fine line between past and future (aka the present) is good
+ * to define clearly.  The value passed to bottom_timer_set() is
+ * the minimum value of bottom_time() at which the timer could
+ * expire.  So if you bottom_timer_set(123), then you could see
+ * top_timer_expiration (123) or top_timer_expiration (125) but
+ * not top_timer_expiration (122) being called.  It is the task of
+ * top_timer_expiration (exptime) to fire interrupts for any timer
+ * whose expiration timer is set to a value <= exptime.  This is
+ * because the value of the head's expiration timer is sent down
+ * through bottom_timer_set().
+ */
 
 
 /* The queue for waiting timer events.  There is no queue for ready
  */
 static irqtimer_t *irqtimer_wait_queue = NULL;
 
-#define tmr_next tmr_irq.irq_next
-
-
 static bool irqtimer_interrupt_blocked = true;
-static bool irqtimer_interrupt_occurred = false; // TODO: highest priority_t
-
-static bool irqtimer_fire_blocked = false;
+static bool irqtimer_interrupt_occurred = false;
 
 
 /* Process a timer interrupt.
  */
-void top_timer_expiration (timing_t exptime) {
+timing_t top_timer_expiration (timing_t exptime) {
+bottom_led_set (LED_IDX_BACKLIGHT, 0);
        if (irqtimer_interrupt_blocked) {
-               printf ("Deferring timer interrupt\n");
                irqtimer_interrupt_occurred = true;
        } else {
-               while (irqtimer_wait_queue && (irqtimer_wait_queue->tmr_expiry < exptime)) {
+               while (irqtimer_wait_queue && TIME_BEFOREQ (irqtimer_wait_queue->tmr_expiry, exptime)) {
                        irqtimer_t *here = irqtimer_wait_queue;
-                       irqtimer_wait_queue = (irqtimer_t *) here->tmr_next;
-                       printf ("Firing IRQ for timer interrupt\n");
+                       irqtimer_wait_queue = here->tmr_next;
+                       here->tmr_next = NULL;
                        irq_fire (&here->tmr_irq);
                }
+               if (irqtimer_wait_queue) {
+                       exptime = irqtimer_wait_queue->tmr_expiry;
+               }
        }
+bottom_led_set (LED_IDX_BACKLIGHT, 1);
+       return exptime;
 }
 
 
-/* Enable or disable a timer interrupt.
+/* Enable or disable a timer interrupt.  This does not actually
+ * stop the hardware interrupt from occurring, but it does stop
+ * the queue from being observed or modified in the interrupt
+ * handler routine.  This facility is useful to allow modifying
+ * the queue without having to take down interrupt handling for
+ * all the other hardware-related processes.  As an optimisation,
+ * the flag irqtimer_interrupt_occurred will record that the
+ * top_timer_expiration() handler was invoked, so that the queue
+ * needs to be revisited.
  */
-void irqtimer_enable (void) {
-#if 0
-       timing_t now = bottom_time ();
-       while (irqtimer_interrupt_occurred) {
-               irqtimer_interrupt_occurred = false;
-               top_timer_expiration (now);
-               irqtimer_interrupt_blocked = false;
-       }
-#endif
+static inline void irqtimer_disable (void) {
+       irqtimer_interrupt_blocked = true;
+}
+static void irqtimer_enable (void) {
        irqtimer_interrupt_blocked = false;
        if (irqtimer_interrupt_occurred) {
-               printf ("Activating deferred timer interrupt\n");
-               timing_t now = bottom_time ();
-               top_timer_expiration (now);
+               timing_t now, next;
+               bottom_printf ("Activating deferred timer interrupt\n");
+               now = bottom_time ();
+               next = top_timer_expiration (now);
+               if (next != now) {
+                       bottom_timer_set (next);
+               }
        }
 }
-inline void irqtimer_disable (void) {
-       irqtimer_interrupt_blocked = true;
-}
 
 
 /* Enqueue an initialised timer structure to the timer wait queue.
@@ -76,10 +136,10 @@ static void irqtimer_enqueue (irqtimer_t *tmr) {
        irqtimer_t **here;
        irqtimer_disable ();
        here = &irqtimer_wait_queue;
-       while ((*here) && ((*here)->tmr_expiry < tmr->tmr_expiry)) {
+       while ((*here) && TIME_BEFOREQ ((*here)->tmr_expiry, tmr->tmr_expiry)) {
                here = (irqtimer_t **) & (*here)->tmr_next;
        }
-       tmr->tmr_next = (void *) *here;
+       tmr->tmr_next = *here;
        (*here) = tmr;
        if (irqtimer_wait_queue == tmr) {
                bottom_timer_set ((*here)->tmr_expiry);
@@ -90,11 +150,16 @@ static void irqtimer_enqueue (irqtimer_t *tmr) {
 /* Setup a new timer by enqueueing its structure in the timer list.
  */
 void irqtimer_start (irqtimer_t *tmr, timing_t delay, irq_handler_t hdl, priority_t prio) {
-       timing_t new_expiry = bottom_time () + delay;
+       tmr->tmr_irq.irq_next = NULL;
        tmr->tmr_irq.irq_handler = hdl;
        tmr->tmr_irq.irq_priority = prio;
-       tmr->tmr_expiry = new_expiry;
-       irqtimer_enqueue (tmr);
+       tmr->tmr_expiry = bottom_time () + delay;       // Always support: irqtimer_restart()
+       if (delay == 0) {
+               tmr->tmr_next = NULL;
+               irq_fire (&tmr->tmr_irq);
+       } else {
+               irqtimer_enqueue (tmr);
+       }
 }
 
 
@@ -127,6 +192,3 @@ void irqtimer_stop (irqtimer_t *tmr) {
        irqtimer_enable ();
 }
 
-
-/* TODO: Initialise this module by registering the top-half timer interrupt handler.
- */
diff --git a/src/net/6bed4.c b/src/net/6bed4.c
new file mode 100644 (file)
index 0000000..dc55cfd
--- /dev/null
@@ -0,0 +1,2 @@
+#include <stdint.h>
+uint32_t ip4_6bed4 = ( (uint32_t) 78) << 24 | ((uint32_t) 47) << 16 | ((uint32_t) 251) << 8 | ((uint32_t) 74 );
index b772eef..3560164 100644 (file)
@@ -1,4 +1,4 @@
 src/net/6bed4.c:
-       printf > $@ '#include <stdint.h>\nuint32_t ip4_6bed4 = ( %d << 24 | %d << 16 | %d << 8 | %d );\n' `echo $(CONFIG_NET_6BED4_SERVER) | sed 's/\./ /g'`
+       printf > $@ '#include <stdint.h>\nuint32_t ip4_6bed4 = ( (uint32_t) %d) << 24 | ((uint32_t) %d) << 16 | ((uint32_t) %d) << 8 | ((uint32_t) %d );\n' `echo $(CONFIG_NET_6BED4_SERVER) | sed 's/\./ /g'`
 
 objs-top-net-y += src/net/core.o src/net/input.o src/net/reply.o src/net/send.o src/net/db.o src/net/6bed4.o
index 5a4d44e..e4ecd1c 100644 (file)
@@ -1,36 +1,51 @@
 /* netcore.c -- Networking core routines.
  *
- * From: Rick van Rein <rick@openfortress.nl>
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
 #include <stdlib.h>
 #include <stdio.h>
-#include <stdarg.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <string.h>
-#include <fcntl.h>
+// #include <fcntl.h>
 
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
+//TODO// #include <sys/types.h>
+//TODO// #include <sys/ioctl.h>
+//TODO// #include <sys/socket.h>
 
-#include <netinet/ip.h>
-#include <netinet/ip6.h>
-#include <netinet/udp.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/icmp6.h>
-#include <net/ethernet.h>
+//TODO// #include <netinet/ip.h>
+//TODO// #include <netinet/ip6.h>
+//TODO// #include <netinet/udp.h>
+//TODO// #include <netinet/ip_icmp.h>
+//TODO// #include <netinet/icmp6.h>
+//TODO// #include <net/ethernet.h>
 
 #include <config.h>
 
 #include <0cpm/cpu.h>
-#include <0cpm/netfun.h>
-#include <0cpm/netdb.h>
 #include <0cpm/irq.h>
 #include <0cpm/timer.h>
-
+#include <0cpm/netinet.h>
+#include <0cpm/netfun.h>
+#include <0cpm/netdb.h>
+#include <0cpm/cons.h>
+#include <0cpm/led.h>  // TODO: only for test purposes, LED_IDX_MESSAGE below
 
 /* Network configuration states */
 
@@ -39,6 +54,7 @@ enum netcfgstate {
        NCS_AUTOCONF,   // A few LAN autoconfiguration attempts
        NCS_DHCPV6,     // A few LAN DHCPv6 attempts
        NCS_DHCPV4,     // A few LAN DHCPv4 attempts
+       NCS_ARP,        // A few gateway-MAC address fishing attempts
        NCS_6BED4,      // A few 6BED4 attempts over IPv4
        NCS_ONLINE,     // Stable online performance
        NCS_RENEW,      // Stable online, but renewing DHCPv6/v4
@@ -50,40 +66,48 @@ enum netcfgstate {
 /* Global variables
  */
 
-static enum netcfgstate boot_state   = NCS_OFFLINE;
-static uint8_t          boot_retries = 1;
+/*TODO static*/ enum netcfgstate boot_state   = NCS_OFFLINE;
+/*TODO static*/ uint8_t          boot_retries = 1;
 
+/* The timer that waits until a next step is to be taken for
+ * bootstrapping the network.  This timer waits half a second
+ * between sending router sollicitations, and so on.
+ */
 static irqtimer_t netboottimer;
 
-extern packet_t rbuf, wbuf;    // TODO: Testing setup
+/* The timer that waits until the next keepalive interval has
+ * occurred, so until a new package has to be sent out far
+ * enough to keep the local firewall or NAT open; NAT in case
+ * of 6bed4 and firewall in the case of normal IPv6.
+ */
+static irqtimer_t keepalivetimer;
+
+/*extern*/ packet_t rbuf, wbuf;        // TODO: Testing setup
 
 extern uint8_t ether_mine [ETHER_ADDR_LEN];
 
+const uint8_t ether_unknown [6] = { 0x00, 0x00, 0x0, 0x00, 0x00, 0x00 };
+
 
-/* netcore_checksum_areas (void *area0, uint16_t len0, ..., NULL)
- * Calculate the Internet checksum over the given areas
+/* Calculate the Internet checksum over the given areas.
+ * This is done iteratively, by calling this function for a number
+ * of different ranges of words.  The length is in bytes, not in
+ * words.  Initialise the checksum to CHECKSUM_ZERO before starting.
  */
-uint16_t netcore_checksum_areas (void *area0, ...) {
-       uint32_t csum = 0;
-       uint16_t *area;
-       va_list pairs;
-       va_start (pairs, area0);
-       area = (uint16_t *) area0;
-       while (area) {
-               uint16_t len = (int16_t) va_arg (pairs, int);
-               while (len > 1) {
-                       csum = csum + ntohs (*area++);
-                       len -= 2;
-               }
-               if (len > 0) {
-                       csum = csum + * (uint8_t *) area;
-               }
-               area = va_arg (pairs, uint16_t *);
+#define CHECKSUM_ZERO 0xffff
+void netcore_checksum_area (uint16_t *checksum, nint16_t *area, uint16_t len) {
+       uint32_t csum = ~ *checksum;
+       while (len > 1) {
+               csum = csum + netget16 (*area);
+               area++;
+               len -= 2;
+       }
+       if (len > 0) {
+               csum = csum + netget8 (*(nint8_t *)area);
        }
-       va_end (pairs);
        csum = (csum & 0xffff) + (csum >> 16);
        csum = (csum & 0xffff) + (csum >> 16);
-       return htons ((uint16_t) ~csum);
+       *checksum = (uint16_t) ~csum;
 }
 
 
@@ -100,103 +124,112 @@ void netcore_send_buffer (intptr_t *mem, uint8_t *wbuf) {
        struct ip6_hdr *ip6 = (void *) mem [MEM_IP6_HEAD];
        struct arphdr  *arp = (void *) mem [MEM_ARP_HEAD];
        struct ethhdr  *eth = (void *) mem [MEM_ETHER_HEAD];
+       uint16_t wlen;
        //
        // Checksum UDPv6 on IPv6
        if (ip6 && udp6) {
-               uint16_t pload6 = htons (IPPROTO_UDP);
-               udp6->len = htons (mem [MEM_ALL_DONE] - mem [MEM_UDP6_HEAD]);
-               ip6->ip6_plen = udp6->len;
-               ip6->ip6_nxt = IPPROTO_UDP;
-               udp6->check = netcore_checksum_areas (
-                               &ip6->ip6_src, 32,
-                               &ip6->ip6_plen, 2,
-                               &pload6, 2,
-                               udp6, 6,
-                               udp6 + 1, (int) htons (udp6->len) - 8,
-                               NULL);
+               nint16_t pload6;
+               uint16_t plen = mem [MEM_ALL_DONE] - mem [MEM_UDP6_HEAD];
+               uint16_t csum = CHECKSUM_ZERO;
+               netset16 (pload6, IPPROTO_UDP);
+               netset16 (udp6->len,     plen);
+               netset16 (ip6->ip6_plen, plen);
+               netset8  (ip6->ip6_nxt, IPPROTO_UDP);
+               netcore_checksum_area (&csum, (nint16_t *) &ip6->ip6_src, 32);
+               netcore_checksum_area (&csum, (nint16_t *) &ip6->ip6_plen, 2);
+               netcore_checksum_area (&csum, (nint16_t *) &pload6, 2);
+               netcore_checksum_area (&csum, (nint16_t *) udp6, 6);
+               netcore_checksum_area (&csum, (nint16_t *) (udp6 + 1), (int) (plen - 8));
+               netset16 (udp6->check, csum);
        }
        //
        // Checksum ICMPv6 on IPv6
        if (ip6 && icmp6) {
-               ip6->ip6_nxt = IPPROTO_ICMPV6;
-               uint16_t pload6 = htons (IPPROTO_ICMPV6);
-               ip6->ip6_plen = htons (mem [MEM_ALL_DONE] - mem [MEM_ICMP6_HEAD]);
-               icmp6->icmp6_cksum = 0;
-               icmp6->icmp6_cksum = netcore_checksum_areas (
-                               &ip6->ip6_src, 32,
-                               &ip6->ip6_plen, 2,
-                               &pload6, 2,
-                               icmp6, (int) mem [MEM_ALL_DONE] - (int) mem [MEM_ICMP6_HEAD],
-                               NULL);
+               nint16_t pload6;
+               uint16_t csum = CHECKSUM_ZERO;
+               netset8 (ip6->ip6_nxt, IPPROTO_ICMPV6);
+               netset16 (pload6, IPPROTO_ICMPV6);
+               netset16 (ip6->ip6_plen, mem [MEM_ALL_DONE] - mem [MEM_ICMP6_HEAD]);
+               netset16 (icmp6->icmp6_cksum, 0);
+               netcore_checksum_area (&csum, (nint16_t *) &ip6->ip6_src, 32);
+               netcore_checksum_area (&csum, (nint16_t *) &ip6->ip6_plen, 2);
+               netcore_checksum_area (&csum, (nint16_t *) &pload6, 2);
+               netcore_checksum_area (&csum, (nint16_t *) icmp6, (int) mem [MEM_ALL_DONE] - (int) mem [MEM_ICMP6_HEAD]);
+               netset16 (icmp6->icmp6_cksum, csum);
        }
        //
        // Checksum UDPv4 under IPv6 (6bed4 tunnel)
        if (udp4) {
-               udp4->len = htons (mem [MEM_ALL_DONE] - mem [MEM_UDP4_HEAD]);
+               netset16 (udp4->len, mem [MEM_ALL_DONE] - mem [MEM_UDP4_HEAD]);
        }
        //
        // Checksum UDPv4 on IPv4
        if (ip4 && udp4) {
-               ip4->protocol = IPPROTO_UDP;
-               uint16_t pload4 = htons (IPPROTO_UDP);
-               ip4->tot_len = htons (20 + ntohs (udp4->len));
-               udp4->check = netcore_checksum_areas (
-                               &ip4->saddr, 8,
-                               &pload4, 2,
-                               &udp4->len, 2,
-                               udp4, 6,
-                               udp4 + 1, (int) ntohs (udp4->len) - 8,
-                               NULL);
+               nint16_t pload4;
+               uint16_t csum = CHECKSUM_ZERO;
+               netset8 (ip4->protocol, IPPROTO_UDP);
+               netset16 (pload4, IPPROTO_UDP);
+               netset16 (ip4->tot_len, 20 + netget16 (udp4->len));
+               netcore_checksum_area (&csum, (nint16_t *) &ip4->saddr, 8);
+               netcore_checksum_area (&csum, (nint16_t *) &pload4, 2);
+               netcore_checksum_area (&csum, (nint16_t *) &udp4->len, 2);
+               netcore_checksum_area (&csum, (nint16_t *) udp4, 6);
+               netcore_checksum_area (&csum, (nint16_t *) (udp4 + 1), (int) netget16 (udp4->len) - 8);
+               netset16 (udp4->check, csum);
        }
        //
        // Checksum ICMPv4
-       if (icmp4) {
-               ip4->tot_len = htons (mem [MEM_ALL_DONE] - mem [MEM_IP4_HEAD]);
-               ip4->protocol = IPPROTO_ICMP;
-               icmp4->icmp_cksum = 0;
-               icmp4->icmp_cksum = netcore_checksum_areas (
-                               icmp4, (int) mem [MEM_ALL_DONE] - (int) mem [MEM_ICMP4_HEAD],
-                               NULL);
+       if (ip4 && icmp4) {
+               uint16_t csum = CHECKSUM_ZERO;
+               netset16 (ip4->tot_len, mem [MEM_ALL_DONE] - mem [MEM_IP4_HEAD]);
+               netset8 (ip4->protocol, IPPROTO_ICMP);
+               netset16 (icmp4->icmp_cksum, 0);
+               netcore_checksum_area (&csum, (nint16_t *) icmp4, (int) mem [MEM_ALL_DONE] - (int) mem [MEM_ICMP4_HEAD]);
+               netset16 (icmp4->icmp_cksum, csum);
        }
        //
        // Checksum IPv4
        if (ip4) {
-               ip4->check = netcore_checksum_areas (
-                               ip4, 10,
-                               &ip4->saddr, 8,
-                               NULL);
+               uint16_t csum = CHECKSUM_ZERO;
+               netcore_checksum_area (&csum, (nint16_t *) ip4, 10);
+               netcore_checksum_area (&csum, (nint16_t *) &ip4->saddr, 8);
+               netset16 (ip4->check, csum);
        }
        //
        // Determine the tunnel prefix info and ethernet protocol
        if (ip4) {
-               eth->h_proto = htons (ETH_P_IP);
+               netset16 (eth->h_proto, ETH_P_IP);
        } else if (ip6) {
-               eth->h_proto = htons (ETH_P_IPV6);
+               netset16 (eth->h_proto, ETH_P_IPV6);
        } else if (arp) {
-               eth->h_proto = htons (ETH_P_ARP);
+               netset16 (eth->h_proto, ETH_P_ARP);
        } else {
                return;
        }
        //
        // Actually have the packet sent
        // TODO: Defer if priority lower than current CPU priority level
-       uint16_t wlen = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+       wlen = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
        if (!bottom_network_send (wbuf, wlen)) {
                // TODO: Queue packet for future delivery
        }
 }
 
 
-/* Send a router solicitation.
+/* Send a router solicitation.  If the binding to use relies
+ * on an IPv4 binding, it will run over a 6BED4 tunnel, and
+ * be sent to the router instead of broadcasted on the LAN.
  */
 static void solicit_router (void) {
        uint8_t *start = wbuf.data;
        intptr_t mem [MEM_NETVAR_COUNT];
+       uint8_t *stop;
+       uint32_t len;
        bzero (mem, sizeof (mem));
        mem [MEM_BINDING6] = (intptr_t) &ip6binding [0];
-       uint8_t *stop = netsend_icmp6_router_solicit (start, mem);
+       stop = netsend_icmp6_router_solicit (start, mem);
        mem [MEM_ALL_DONE] = (intptr_t) stop;
-       uint32_t len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+       len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
        if ((len > 0) && (len < 1500 + 18)) {
                netcore_send_buffer (mem, wbuf.data);
        }
@@ -208,10 +241,12 @@ static void solicit_router (void) {
 static void get_dhcp4_lease (void) {
        uint8_t *start = wbuf.data;
        intptr_t mem [MEM_NETVAR_COUNT];
+       uint8_t *stop;
+       uint32_t len;
        bzero (mem, sizeof (mem));
-       uint8_t *stop = netsend_dhcp4_discover (start, mem);
+       stop = netsend_dhcp4_discover (start, mem);
        mem [MEM_ALL_DONE] = (intptr_t) stop;
-       uint32_t len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+       len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
        if ((len > 0) && (len < 1500 + 18)) {
                netcore_send_buffer (mem, wbuf.data);
        }
@@ -223,40 +258,135 @@ static void get_dhcp4_lease (void) {
 static void get_dhcp6_lease (void) {
        uint8_t *start = wbuf.data;
        intptr_t mem [MEM_NETVAR_COUNT];
+       uint8_t *stop;
+       uint32_t len;
        bzero (mem, sizeof (mem));
-       uint8_t *stop = netsend_dhcp6_solicit (start, mem);
+       stop = netsend_dhcp6_solicit (start, mem);
        mem [MEM_ALL_DONE] = (intptr_t) stop;
-       uint32_t len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+       len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
        if ((len > 0) && (len < 1500 + 18)) {
                netcore_send_buffer (mem, wbuf.data);
        }
 }
 
 
-/* Is an IPv6 address available?
+/* Figure out the MAC address of any routers or nameservers
+ * that are currently undefined for IPv4.  This may send out
+ * more than one query, or none at all.
+ */
+static void get_local_mac_addresses (void) {
+       uint8_t *start;
+       intptr_t mem [MEM_NETVAR_COUNT];
+       uint8_t *stop;
+       uint32_t len;
+       int bndidx;
+       ip4peer_t peernr;
+       for (bndidx = 0; bndidx < IP4BINDING_COUNT; bndidx++) {
+               for (peernr = 0; peernr < IP4_PEER_COUNT; peernr++) {
+ht162x_putchar (peernr, '0', true);
+                       if (!ip4binding [bndidx].ip4addr) {
+                               continue;
+                       }
+                       if (!ip4binding [bndidx].ip4mask) {
+                               continue;
+                       }
+                       if ((ip4binding [bndidx].ip4addr ^ ip4binding [bndidx].ip4peer [peernr]) & ip4binding [bndidx].ip4mask) {
+                               continue;
+                       }
+                       if (memcmp (ip4binding [bndidx].ip4peermac [IP4_PEER_GATEWAY], ether_unknown, ETHER_ADDR_LEN) == 0) {
+ht162x_putchar (peernr, '1', true);
+                               bzero (mem, sizeof (mem));
+                               mem [MEM_IP4_SRC] = ip4binding [bndidx].ip4addr;
+                               mem [MEM_IP4_DST] = ip4binding [bndidx].ip4peer [peernr];
+                               start = wbuf.data;
+                               stop = netsend_arp_query (start, mem);
+                               mem [MEM_ALL_DONE] = (intptr_t) stop;
+                               len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+                               if ((len > 0) && (len < 1500 + 18)) {
+ht162x_putchar (peernr, '2', true);
+                                       netcore_send_buffer (mem, wbuf.data);
+ht162x_putchar (peernr, '3', true);
+                               }
+                       }
+               }
+       }
+}
+
+
+/* Is an IPv6 address available?  >= 0 is an index, -1 means no address.
  */
-static bool have_ipv6 (void) {
+static int have_ipv6 (void) {
        int i;
        for (i=0; i < IP6BINDING_COUNT; i++) {
-               if (ip6binding [i].flags & (I6B_TENTATIVE | I6B_EXPIRED) == 0) {
-                       return true;
+               if ((ip6binding [i].flags & (I6B_DEFEND_ME | I6B_EXPIRED)) == I6B_DEFEND_ME) {
+ht162x_led_set (3, 1, true);   // Shows up as PM
+                       return i;
+               }
+       }
+ht162x_led_set (3, 0, true);   // Shows up as PM
+       return -1;
+}
+
+/* Is an IPv4 address available?  >= 0 is an index, -1 means no address.
+ */
+static int have_ipv4 (void) {
+       int i;
+       for (i=0; i < IP4BINDING_COUNT; i++) {
+               if ((ip4binding [i].ip4addr & ip4binding [i].ip4mask) != 0) {
+ht162x_led_set (4, 1, true);
+                       return i;
                }
        }
-       return false;
+ht162x_led_set (4, 0, true);
+       return -1;
 }
 
-/* Is an IPv4 address available?
+/* Is there an IPv4 gateway available, with a MAC address?  >= 0 is an index, -1 means no address.
  */
-static bool have_ipv4 (void) {
+static int have_ipv4_gateway_mac (void) {
        int i;
        for (i=0; i < IP4BINDING_COUNT; i++) {
                if (ip4binding [i].ip4addr != 0) {
-                       return true;
+                       if (memcmp (ip4binding [i].ip4peermac [IP4_PEER_GATEWAY], ether_unknown, ETHER_ADDR_LEN) != 0) {
+ht162x_led_set (10, 1, true);  // Shows up as an arrow
+                               return i;
+                       }
                }
        }
-       return false;
+ht162x_led_set (10, 0, true);  // Shows up as an arrow (off)
+       return -1;
 }
 
+/* Keep a 6bed4 link alive, by sending an empty UDP package each 30 seconds.
+ */
+static void netcore_keepalive (irq_t *tmr) {
+       uint8_t *start;
+       intptr_t mem [MEM_NETVAR_COUNT];
+       uint8_t *stop;
+       uint32_t len;
+       int bndidx;
+       for (bndidx=0; bndidx < IP6BINDING_COUNT; bndidx++) {
+               if (!(ip6binding [bndidx].flags & I6B_DEFEND_ME)) {
+                       continue;
+               }
+               if ((ip6binding [bndidx].flags & I6B_ROUTE_SOURCE_6BED4_MASK) && (ip6binding [bndidx].ip4binding)) {
+                       bzero (mem, sizeof (mem));
+                       //OK// mem [MEM_UDP6_SRC_PORT] = 0;
+                       //OK// mem [MEM_UDP6_DST_PORT] = 0;
+                       mem [MEM_BINDING6] = (intptr_t) &ip6binding [bndidx];
+                       mem [MEM_IP6_DST] = (intptr_t) ip6binding [bndidx].ip6addr; // Brutal: me!
+                       mem [MEM_ETHER_DST] = (intptr_t) ip6binding [bndidx].ip4binding->ip4peermac [0];
+                       stop = netsend_udp6 (start, mem);       // No UDP payload!
+                       mem [MEM_ALL_DONE] = (intptr_t) stop;
+                       len = mem [MEM_ALL_DONE] - mem [MEM_ETHER_HEAD];
+                       if ((len > 0) && (len < 1500 + 18)) {
+                               netcore_send_buffer (mem, wbuf.data);
+                       }
+
+               }
+       }
+       irqtimer_restart ((irqtimer_t *) tmr, TIME_SEC (30));
+}
 
 /* Boot the network: Obtain an IPv6 address, possibly based on an IPv4
  * and a 6bed4 tunnel.  This is implemented as a state diagram made
@@ -272,9 +402,10 @@ static bool have_ipv4 (void) {
  *     - first try to reuse an older IPv4 address (TODO)
  *     - when an IPv4 address was acquired, autoconfigure 6bed4 over it
  */
-bool netcore_bootstrap_step (irq_t *tmrirq) {
-       printf ("Taking a step in network bootstrapping\n");
-       timing_t delay = 0;
+void netcore_bootstrap_step (irq_t *tmrirq) {
+       timing_t delay;
+       bottom_printf ("Taking a step in network bootstrapping\n");
+       delay = 0;
        if (boot_retries > 0) {
                boot_retries--;
        } else {
@@ -287,67 +418,104 @@ bool netcore_bootstrap_step (irq_t *tmrirq) {
        }
        switch (boot_state) {
        case NCS_DHCPV4:        // A few LAN DHCPv4 attempts
-               if (!have_ipv4 ()) {
+               if (have_ipv4 () == -1) {
                        get_dhcp4_lease ();
                        delay = TIME_MSEC(5000);
+                       boot_retries = 2;
+                       break;
+               }
+               boot_state = NCS_ARP;
+               boot_retries = 3;
+               // Continue into NCS_ARP for gateway location
+       case NCS_ARP:           // A few gateway-MAC address fishing attempts
+               if (have_ipv4_gateway_mac () == -1) {
+                       get_local_mac_addresses ();
+                       delay = TIME_MSEC(250);
                        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];
-                       ip6binding [0].flags |= I6B_ROUTE_SOURCE_6BED4_FLAG;
+               if (have_ipv6 () == -1) {
+                       uint8_t v4bnd = have_ipv4_gateway_mac ();
+                       if (v4bnd == -1) {
+                               // Error, danger, panic.  Bail out, try again.
+                               boot_state = NCS_DHCPV4;
+                               boot_retries = 2;
+                               delay = TIME_MSEC(5000);
+                               break;
+                       }
+                       ip6binding [0].ip4binding = &ip4binding [v4bnd];
+                       ip6binding [0].flags |= I6B_ROUTE_SOURCE_6BED4_MASK;
                }
                // Continue into NCS_AUTOCONF for Router Solicitation
        case NCS_AUTOCONF:      // A few LAN autoconfiguration attempts
-               if (have_ipv6 ()) {
-                       return true;
+               if (have_ipv6 () >= 0) {
+                       return;
                }
                solicit_router ();
-               delay = TIME_MSEC(500);
+               delay = TIME_MSEC(1000);
                break;
        case NCS_DHCPV6:        // A few LAN DHCPv6 attempts
-               if (have_ipv6 ()) {
-                       return true;
+               if (have_ipv6 () >= 0) {
+                       return;
                }
                get_dhcp6_lease ();
                delay = TIME_MSEC(1000);
                break;
        case NCS_ONLINE:        // Stable online performance
-               return true;
+               return;
        case NCS_RENEW:         // Stable online, but renewing DHCPv6/v4
                // TODO: Inspect timers or resend renewal request
-               return true;
+               return;
        case NCS_OFFLINE:       // Await top_network_online()
                break;
        case NCS_PANIC:         // Not able to bootstrap anything
                // delay = TIME_MIN(15);
                // break;
-               return true;
+               return;
        default:
                break;
        }
        irqtimer_restart ((irqtimer_t *) tmrirq, delay);
-       return true;
 }
 
 /* Initiate the bootstrapping process, returning its closure
  */
 void netcore_bootstrap_initiate (void) {
+       netdb_initialise ();
+       irqtimer_stop (&netboottimer);  // Initially ignored, very useful on restart
        bzero (&netboottimer, sizeof (netboottimer));
        boot_retries = 3 + (ether_mine [5] & 0x03);     // 3..7
        boot_state = NCS_AUTOCONF;
-       printf ("Initiating network bootstrapping procedures\n");
+       bottom_printf ("Initiating network bootstrapping procedures\n");
+       irqtimer_start (&netboottimer, 0, netcore_bootstrap_step, CPU_PRIO_LOW);
+       //TODO// irqtimer_start (&keepalivetimer, TIME_SEC(30), netcore_keepalive, CPU_PRIO_LOW);
+}
+
+/* Signal that bootstrapping has reached a successful state
+ */
+void netcore_bootstrap_success (void) {
+       irqtimer_stop (&netboottimer);
+       boot_state = NCS_ONLINE;
+}
+
+/* Signal that bootstrapping must be restarted (expiration due).
+ */
+void netcore_bootstrap_restart (void) {
+       boot_retries = 3 + (ether_mine [5] & 0x03);     // 3..7
+       boot_state = NCS_AUTOCONF;
        irqtimer_start (&netboottimer, 0, netcore_bootstrap_step, CPU_PRIO_LOW);
 }
 
 /* Shutdown the bootstrapping process, if any
  */
 void netcore_bootstrap_shutdown (void) {
+       irqtimer_stop (&netboottimer);
+       //TODO// irqtimer_stop (&keepalivetimer);
        boot_retries = 1;
        boot_state   = NCS_OFFLINE;
-       irqtimer_stop (&netboottimer);
+       netdb_initialise ();
 }
 
index 3190ca4..b9d66fb 100644 (file)
@@ -1,27 +1,48 @@
 /* netdb.c -- Network Database -- Storage for network bindings and addresses.
  *
- * From: Rick van Rein <rick@openfortress.nl>
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
+#include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <stdarg.h>
 
-#include <time.h>
+// #include <time.h>
 
-#include <netinet/icmp6.h>
+// #include <netinet/icmp6.h>
 
 #include <config.h>
 
 #include <0cpm/cpu.h>
+#include <0cpm/irq.h>
+#include <0cpm/timer.h>
+#include <0cpm/netinet.h>
 #include <0cpm/netfun.h>
 #include <0cpm/netdb.h>
+#include <0cpm/cons.h>
 
 
 /* A few useful global variables
  */
 
 extern uint8_t ether_mine [];
+extern const uint8_t ether_unknown [];
 
 uint32_t localtime_ofs = 0;
 
@@ -55,26 +76,50 @@ void util_mac2ifid (uint8_t *ip6address, const uint8_t *mac) {
 }
 
 
+/* When creating a new address, the tentative address must be probed
+ * through neighbour discovery, followed by a small-period wait.  This
+ * routine is invoked at the end of this waiting period.
+ */
+void tentative_wait_passed (irq_t *irq) {
+       struct ip6binding *bnd = (struct ip6binding *) irq;
+       bnd->flags |=  I6B_DEFEND_ME;
+       bnd->flags &= ~I6B_TENTATIVE;
+       netcore_bootstrap_success ();
+       // TODO: Set expiration timer
+}
+
+
 /* An IPv6 Router Advertisement was received.  Process it by storing
  * the offered prefix.
  */
 // TODO: Process retractions (life set to 0)
 // TODO: Generate ND packet for DAD and start timeout
 uint8_t *netdb_router_advertised (uint8_t *pout, intptr_t *mem) {
-       printf ("Received & Processing: Router Advertisement\n");
-       struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) mem [MEM_ICMP6_HEAD];
-       uint32_t routerlife = (uint32_t) icmp6->icmp6_data16 [1];
-       uint32_t preferlife = (uint32_t) 0xffffffff;
-       uint8_t *options = icmp6->icmp6_data8 + 12;
+       struct icmp6_hdr *icmp6;
+       uint32_t routerlife;
+       uint32_t preferlife;
+       uint8_t *options;
        uint8_t *ip6uplink_mac = NULL;
        uint8_t *ip6prefix = NULL;
        int ip6prefixlen = -1;
        int best_pref = -1, cur_pref = -1;
        bool ok = true;
+extern uint8_t bad;
        bool needDHCP = true;
+       uint8_t ip6address [16];
+       uint16_t bindflags;
+       int bindidx = 0; // TODO: Actually find a suitable entry to update
+bad = 0;
+       bottom_printf ("Received & Processing: Router Advertisement\n");
+       icmp6 = (struct icmp6_hdr *) mem [MEM_ICMP6_HEAD];
+       needDHCP = netget8 (icmp6->icmp6_data8 [1]) >> 7;
+       routerlife = (uint32_t) netget16 (icmp6->icmp6_data16 [1]);
+       preferlife = (uint32_t) 0xffffffff;
+       options = (uint8_t *) (icmp6->icmp6_data8 + 12);
        while (ok && (mem [MEM_ALL_DONE] > (intptr_t) options)) {
                if (((intptr_t) options) + 8 * options [1] > mem [MEM_ALL_DONE]) {
                        ok = false;
+bad = 101;
                        break;
                }
                switch (options [0] + 256 * options [1]) {
@@ -82,9 +127,11 @@ uint8_t *netdb_router_advertised (uint8_t *pout, intptr_t *mem) {
                        ip6uplink_mac = options + 2;
                        break;
                case ND_OPT_MTU + 256:
-                       if (ntohl (*(uint32_t *)(options + 4)) < 1280) {
+                       //TODO// if (ntohl (*(uint32_t *)(options + 4)) < 1280) { ...}
+                       if (netget32 (*(nint32_t *) (options + 4)) < 1280) {
                                // MTU under 1280 is illegal, higher ignored
                                ok = false;
+bad = 102;
                                break;
                        }
                        break;
@@ -93,14 +140,13 @@ uint8_t *netdb_router_advertised (uint8_t *pout, intptr_t *mem) {
                        // best one continues.
                        // Autoconfiguration: 8 + 2 * prefix_pref_if_any
                        // DHCPv6: 0
-                       if (options [3] & 0x80) {
+                       if (needDHCP) {
                                // we prefer autoconfiguration, so DHCPv6 ranks low
                                cur_pref = 0;
                        } else {
                                // preferences according to RFC 4191
                                static int preferencemap [4] = { 8, 10, /*reserved:*/ 8, 6 };
                                cur_pref = preferencemap [(options [3] >> 3) & 0x03];
-                               needDHCP = false;
                        }
                        // Accept only /64 or /112 prefixes, prefer /64
                        if (options [2] == 64) {
@@ -113,33 +159,42 @@ uint8_t *netdb_router_advertised (uint8_t *pout, intptr_t *mem) {
                                break;
                        }
                        // Copy settings for this prefix, as it is the best
-                       preferlife = ntohl (*(uint32_t *)(options+8));
+                       //TODO// preferlife = ntohl (*(uint32_t *)(options+8));
+                       preferlife = netget32 (*(nint32_t *) (options+8));
                        ip6prefix = options + 16;
                        ip6prefixlen = options [2];
                        best_pref = cur_pref;
                        break;
+               //TODO// ND_OPT_RDNSS
                default:
-                       ok = false;
+                       //TODO:DONT_PANIC_BUT_BE_GENTLE// ok = false;
+//TODO:DONT_PANIC_BUT_BE_GENTLE// bad = 103;
                        break;
                }
                options = options + 8 * options [1];
        }
        ok = ok && (mem [MEM_ALL_DONE] == (intptr_t) options);
+if ((bad==0) && !ok) bad = 111;
        ok = ok && (best_pref >= 0);
+if ((bad==0) && !ok) bad = 112;
+       ok = ok && (routerlife > 300);
+if ((bad==0) && !ok) bad = 113;
        if (!ok) {
+//TODO:TEST// ht162x_led_set (15, 0, true);    // shown as (101)
                return NULL;
        }
+bad = best_pref;
        // Now setup the prefix according one of three cases:
        // 0. The only option is to use DHCP6
        // 1. /112 prefix on 6bed4 -> interface-id = 0x0001
        // 2. /64  prefix on LAN   -> interface-id = EIU64(MAC)
        // 3. /112 prefix on LAN   -> interface-id = MAC-based, >= 0x0002
-       uint8_t ip6address [16];
-       uint16_t bindflags = I6B_ROUTE_SOURCE_AUTOCONF | best_pref;
+       bindflags = I6B_ROUTE_SOURCE_AUTOCONF | best_pref;
        memcpy (ip6address, ip6prefix, 16);
        if (needDHCP) {
                // Case 0. Must use DHCP6
                // Do not memorise, as DHCP6 is a fallback anyway
+bad = 121;
                return NULL;
        } else if (mem [MEM_6BED4_PLOAD] != 0) {
                // Case 1. /112 over 6bed4, interface-id 0x0001
@@ -148,7 +203,7 @@ uint8_t *netdb_router_advertised (uint8_t *pout, intptr_t *mem) {
                }
                ip6address [14] = 0x00;
                ip6address [15] = 0x01;
-               bindflags |= I6B_ROUTE_SOURCE_6BED4_FLAG;
+               bindflags |= I6B_ROUTE_SOURCE_6BED4_MASK;
        } else if (ip6prefixlen == 112) {
                // Case 2. /112 over LAN, interface-id constructed:
                //         Addresses are random-ish, but replayable
@@ -166,9 +221,10 @@ uint8_t *netdb_router_advertised (uint8_t *pout, intptr_t *mem) {
                util_mac2ifid (ip6address, ether_mine);
                bindflags |= I6B_TENTATIVE;
        }
+//TODO:TEST// ht162x_led_set (15, 1, true);    // shown as (101)
        // Now find an entry in the routing table for this tentative
        // address and start up duplicate address detection if needed
-       int bindidx = 0; // TODO: Actually find a suitable entry to update
+       irqtimer_stop (&ip6binding [bindidx].timer); // Just in case
        ip6binding [bindidx].next = NULL;
        bzero (&ip6binding [bindidx], sizeof (ip6binding [bindidx]));
        memcpy (ip6binding [bindidx].ip6addr, ip6address, 16);
@@ -178,15 +234,22 @@ uint8_t *netdb_router_advertised (uint8_t *pout, intptr_t *mem) {
                util_mac2ifid (ip6binding [bindidx].ip6uplink, ip6uplink_mac);
        }
        ip6binding [bindidx].ip6timeout = 0xffffffff;           //TODO
-       if (bindflags & I6B_ROUTE_SOURCE_6BED4_FLAG) {
+       if (bindflags & I6B_ROUTE_SOURCE_6BED4_MASK) {
                ip6binding [bindidx].ip4binding = &ip4binding[0]; //TODO:mk_dyn
        }
        ip6binding [bindidx].flags = bindflags;
-       // Finally, if needed, send a packet for duplicate address detection
-       if (ip6binding [bindidx].flags & I6B_TENTATIVE) {
+       // Finally, send a packet for duplicate address detection OR report success
+       if (bindflags & I6B_TENTATIVE) {
                mem [MEM_BINDING6] = (intptr_t) &ip6binding [bindidx];
-               return netsend_icmp6_ngb_sol (pout, mem);
+               pout = netsend_icmp6_ngb_sol (pout, mem);
+               if (pout) {
+                       irqtimer_start (&ip6binding [bindidx].timer, TIME_MSEC (500), tentative_wait_passed, CPU_PRIO_LOW);
+               }
+               //TODO: else irqtimer_start (...expiration...)
+               return pout;
        } else {
+               ip6binding [bindidx].flags |= I6B_DEFEND_ME;
+               netcore_bootstrap_success ();
                return NULL;
        }
 }
@@ -194,44 +257,44 @@ uint8_t *netdb_router_advertised (uint8_t *pout, intptr_t *mem) {
 /* A neighbour advertisement was received.  Store it for future reference.
  */
 uint8_t *netdb_neighbour_advertised (uint8_t *pout, intptr_t *mem) {
-       printf ("Received: Neighbour Advertisement\n");
-       //TODO -- embodyment of this function//
+       bottom_printf ("Received: Neighbour Advertisement\n");
+       //TODO -- embodyment of this function -- remove tentative, possibly defend territory //
        return NULL;
 }
 
 /* DHCPv4 sends an acknowledgement.  Create a ip6binding for that.
  */
 uint8_t *netdb_dhcp4_ack (uint8_t *pout, intptr_t *mem) {
-       printf ("Received: DHCP4 ACK\n");
-       uint8_t *opt = (uint8_t *) (mem [MEM_DHCP4_HEAD] + 240);
+       uint8_t *opt;
        static const uint8_t cookie [4] = { 99, 130, 83, 99 };
+       int bndidx = 0; //TODO -- select an ip4binding dynamically?
+       bottom_printf ("Received: DHCP4 ACK\n");
+       opt = (uint8_t *) (mem [MEM_DHCP4_HEAD] + 240);
        if (memcmp (opt - 4, cookie, 4) != 0) {
                return NULL;    /* No options? */
        }
-       //TODO -- select an ip4binding dynamically?
-       int bndidx = 0;
        bzero (&ip4binding [bndidx], sizeof (struct ip4binding));
-       ip4binding [bndidx].ip4addr = htonl (* (uint32_t *) (mem [MEM_DHCP4_HEAD] + 16));
+       ip4binding [bndidx].ip4addr = netget32 (* (nint32_t *) (mem [MEM_DHCP4_HEAD] + 16));
        // Security note: The following settings assume that the DHCP4 ACK
        // contains proper lengths.  If not, the only problem is that bad
        // network addresses are copied, which is not a severe problem.
        while (*opt != 255) {
                switch (*opt) {
                case 1:         /* subnet mask */
-                       ip4binding [bndidx].ip4mask = * (uint32_t *) (opt + 2);
+                       ip4binding [bndidx].ip4mask = netget32 (*(nint32_t *) (opt + 2));
                        break;
                case 3:         /* router */
-                       ip4binding [bndidx].ip4gateway = * (uint32_t *) (opt + 2);
+                       ip4binding [bndidx].ip4peer [IP4_PEER_GATEWAY] = netget32 (*(nint32_t *) (opt + 2));
                        break;
                case 6:         /* DNS server(s) */
-                       ip4binding [bndidx].ip4dns [0] = * (uint32_t *) (opt + 2);
-                       ip4binding [bndidx].ip4dns [1] = * (uint32_t *) (opt + 2 + opt [1] - 4);
+                       ip4binding [bndidx].ip4peer [IP4_PEER_DNS0] = netget32 (*(nint32_t *) (opt + 2));
+                       ip4binding [bndidx].ip4peer [IP4_PEER_DNS1] = netget32 (*(nint32_t *) (opt + 2 + opt [1] - 4));
                        break;
                case 2:         /* Local time offset */
-                       localtime_ofs = ntohl (* (uint32_t *) (opt + 2));
+                       localtime_ofs = netget32 (*(nint32_t *) (opt + 2));
                        break;
                case 58:        /* Renewal time */
-                       ip4binding [bndidx].ip4timeout = time (NULL) + ntohl (* (uint32_t *) (opt + 2));
+                       ip4binding [bndidx].ip4timeout = time (NULL) + netget32 (*(nint32_t *) (opt + 2));
                        break;
                case 0:         /* Padding, single byte */
                        opt++;
@@ -240,8 +303,9 @@ uint8_t *netdb_dhcp4_ack (uint8_t *pout, intptr_t *mem) {
                case 59:        /* Rebinding time */
                case 54:        /* DHCP server identifier */
                case 51:        /* IP address lease time */
+               case 35:        /* DHCP message type */
                default:
-                       break;
+                       break;  // Ignore, and continue with the next option
                }
        
                opt = opt + 2 + opt [1];
@@ -252,16 +316,83 @@ uint8_t *netdb_dhcp4_ack (uint8_t *pout, intptr_t *mem) {
 /* DHCPv4 sends a negative acknowledgement.  Whatever :)
  */
 uint8_t *netdb_dhcp4_nak (uint8_t *pout, intptr_t *mem) {
-       printf ("Received: DHCP4 NAK\n");
+       bottom_printf ("Received: DHCP4 NAK\n");
        // Drop this, it is non-information to us
        return NULL;
 }
 
+/* ARP sends a mapping from IPv4 address to MAC address.
+ */
+uint8_t *netdb_arp_reply (uint8_t *pkt, intptr_t *mem) {
+       struct ether_arp *arp = (struct ether_arp *) mem [MEM_ARP_HEAD];
+       int bndidx;
+       ip4peer_t peernr;
+       uint32_t ip4offer = (uint32_t) mem [MEM_IP4_SRC];
+       nint8_t *ip4mac = arp->arp_sha;
+       if (memcmp (ip4mac, ether_unknown, ETHER_ADDR_LEN) == 0) {
+               return NULL;
+       }
+       bottom_printf ("Received: ARP\n");
+       for (bndidx = 0; bndidx < IP4BINDING_COUNT; bndidx++) {
+               for (peernr = 0; peernr < IP4_PEER_COUNT; peernr++) {
+                       if (ip4binding [bndidx].ip4peer [peernr] == ip4offer) {
+                               memcpy (ip4binding [bndidx].ip4peermac [peernr], ip4mac, ETHER_ADDR_LEN);
+                       }
+               }
+       }
+       return NULL;
+}
+
+/* DHCPv6 sends an offer; recurse over the options offered
+ */
+void netdb_dhcp6_recurse_options (nint16_t *dhcp6opts, uint16_t optlen) {
+       while (optlen > 4) {
+               uint16_t opttag = netget16 (dhcp6opts [0]);
+               uint16_t nextlen = 4 + netget16 (dhcp6opts [1]);
+               if (nextlen > optlen) {
+                       break;
+               }
+               switch (opttag) {
+               case 3:         /* OPTION_IA_NA, contains OPTION_IAADDR */
+                       if (nextlen > 16) {
+                               netdb_dhcp6_recurse_options (dhcp6opts +  8, optlen - 16);
+                       }
+                       break;
+               case 4:         /* OPTION_IA_TA, contains OPTION_IAADDR */
+                       if (nextlen > 8) {
+                               netdb_dhcp6_recurse_options (dhcp6opts +  4, optlen -  8);
+                       }
+                       break;
+               case 5:         /* OPTION_IAADDR */
+                       if (nextlen >= 28) {
+                               uint8_t bindidx = 0; /*TODO*/
+                               //TODO: Properly process offer, setup as temporary until Reply
+                               irqtimer_stop (&ip6binding [bindidx].timer); // Just in case
+                               bzero (&ip6binding [bindidx], sizeof (ip6binding [bindidx]));
+                               memcpy (ip6binding [bindidx].ip6addr, dhcp6opts + 2, 16);
+                               ip6binding [bindidx].ip6timeout = bottom_time () + netget32 (*(nint32_t *) (dhcp6opts+12));
+                               ip6binding [bindidx].flags = I6B_ROUTE_SOURCE_DHCP | I6B_TENTATIVE;
+                               netdb_dhcp6_recurse_options (dhcp6opts + 14, optlen - 28);
+                       }
+                       break;
+               /* TODO: Nameservers */
+               /* TODO: Router */
+               default:
+                       break;
+               }
+               dhcp6opts += nextlen >> 1;
+               optlen -= nextlen;
+       }
+}
+
 /* DHCPv6 sends a reply to confirm allocation of an IPv6 address
  */
 uint8_t *netdb_dhcp6_reply (uint8_t *pout, intptr_t *mem) {
-       // TODO: Validate offer to be mine + store configuration data
-       printf ("Received: DHCP6 REPLY\n");
+       // TODO: Validate offer to be mine
+       uint8_t bindidx = 0;    // TODO: Proper binding
+       bottom_printf ("Received: DHCP6 REPLY\n");
+       ip6binding [bindidx].flags |=  I6B_DEFEND_ME;
+       ip6binding [bindidx].flags &= ~I6B_TENTATIVE;
        return NULL;
 }
 
@@ -269,7 +400,7 @@ uint8_t *netdb_dhcp6_reply (uint8_t *pout, intptr_t *mem) {
  */
 uint8_t *netdb_dhcp6_reconfigure (uint8_t *pout, intptr_t *mem) {
        // TODO: Validate offer to be mine + update configuration data
-       printf ("Received: DHCP6 RECONFIGURE\n");
+       bottom_printf ("Received: DHCP6 RECONFIGURE\n");
        return NULL;
 }
 
index 0ba9aaf..06c65a5 100644 (file)
@@ -1,6 +1,24 @@
 /* netinput.c
  *
- * Process networked input and select actions to take.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* Process networked input and select actions to take.
  *
  * The "assembly language" used below is the BPF pseudo-language,
  * documented in
  */
 
 
+#include <stdlib.h>
 #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 <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>
 
 #include <0cpm/cpu.h>
+#include <0cpm/netinet.h>
 #include <0cpm/netcmd.h>
 #include <0cpm/netfun.h>
 
  */
 
 #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(i, t) if (fromhere < sizeof (t)) return NULL; mem [i] = (intptr_t) (t *) here;
 #define store_forward(i, t) store(i,t) forward(t)
 #ifndef get08
-#  define get08(o) (here [o])
+#  define get08(o) ((uint8_t) here [o])
 #endif
 #ifndef get16
-#  define get16(o) ((here [o] << 8) | here [o+1])
+#  define get16(o) ((((uint16_t) here [o]) << 8) | ((uint16_t) here [o+1]))
 #endif
 #ifndef get32
-#  define get32(o) ((here [o] << 24) | (here [o+1] << 16) | (here [o+2] << 8) | here [o+3])
+#  define get32(o) ((((uint32_t) here [o]) << 24) | (((uint32_t) here [o+1]) << 16) | (((uint32_t) here [o+2]) << 8) | ((uint32_t) here [o+3]))
 #endif
 
 intptr_t netinput (uint8_t *pkt, uint16_t pktlen, intptr_t *mem) {
 
        register uint8_t *here = pkt;
        register uint16_t fromhere = pktlen;
+       uint16_t ethertp;
+       uint16_t arpproto;
+       uint32_t arpdetails;
+       uint8_t ip4_ptype;
+       uint16_t icmp4_type_code;
+       uint16_t udp4_src;
+       uint16_t udp4_dst;
+       uint32_t dhcp4_magic_cookie;
+       uint8_t ip6_nxthdr;
+       uint16_t icmp6_type_code;
+       uint16_t udp6_src;
+       uint16_t udp6_dst;
+       uint8_t dhcp6_tag;
+       uint16_t dnssd_flags;
 
        //
        // Store the end of the entire packet
-       mem [MEM_ALL_DONE] = &pkt [pktlen];
+       mem [MEM_ALL_DONE] = (intptr_t) &pkt [pktlen];
 
        //
        // Store the ethernet header
-       uint16_t ethertp = get16 (12);
+       ethertp = get16 (12);
        if (ethertp == 0x8100) {
                struct ethhdrplus { struct ethhdr std; uint8_t ext8021q [4]; };
                store_forward (MEM_ETHER_HEAD, struct ethhdrplus);
@@ -139,19 +173,24 @@ intptr_t netinput (uint8_t *pkt, uint16_t pktlen, intptr_t *mem) {
 
        //
        // Accept ARP reply and query messages translating IPv4 to MAC
-       uint16_t arpproto;
 netin_ARP_sel:
        arpproto = get16 (2);
+ht162x_led_set (4, 1, true); // Chinese top symbol
        if (arpproto != 0x0800) return NULL;
-       store (MEM_ARP_HEAD, struct arphdr);
+ht162x_led_set (5, 1, true); // Chinese bottom symbol
+       store (MEM_ARP_HEAD, struct ether_arp);
        mem [MEM_IP4_SRC] = get32 (14);
        mem [MEM_IP4_DST] = get32 (24);
-       uint32_t arpdetails = get32 (4);
+       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;
+       case 0x06040001:
+ht162x_led_set (4, 0, true); // Chinese top symbol (off)
+                        return (intptr_t) netreply_arp_query;
+       case 0x06040002:
+ht162x_led_set (5, 0, true); // Chinese bottom symbol (off)
+                        return (intptr_t) netdb_arp_reply;
        default: return NULL;
        }
 
@@ -162,9 +201,9 @@ netin_IP4_sel:
        if (get08 (0) != 0x45) return NULL;
        mem [MEM_IP4_SRC] = get32 (12);
        mem [MEM_IP4_DST] = get32 (15);
-       uint8_t ip4_ptype = get08 (9);
+       ip4_ptype = get08 (9);
        forward (struct iphdr);
-       mem [MEM_IP4_PLOAD] = here;
+       mem [MEM_IP4_PLOAD] = (intptr_t) here;
        //
        // Jump to a handler for the payload type
        switch (ip4_ptype) {
@@ -175,11 +214,10 @@ netin_IP4_sel:
 
        //
        // 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;
+       case 8 << 8: return (intptr_t) netreply_icmp4_echo_req;
        default: return NULL;
        }
 
@@ -187,10 +225,10 @@ netin_ICMP4_sel:
        // 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);
+       udp4_src = mem [MEM_UDP4_SRC_PORT] = get16 (0);
+       udp4_dst = mem [MEM_UDP4_DST_PORT] = get16 (2);
        forward (struct udphdr);
-       mem [MEM_UDP4_PLOAD] = here;
+       mem [MEM_UDP4_PLOAD] = (intptr_t) here;
        //
        // Choose a handler based on port
        if (udp4_src == 3653) goto netin_6BED4_sel;
@@ -203,7 +241,7 @@ netin_UDP4_sel:
 netin_DHCP4_sel:
        store (MEM_DHCP4_HEAD, uint8_t);
        if (fromhere < 236 + 4) return NULL;
-       uint32_t dhcp4_magic_cookie = get32 (236);
+       dhcp4_magic_cookie = get32 (236);
        if (dhcp4_magic_cookie != 0x63825363) return NULL;      // TODO: BOOTP?
        here     += 236 + 4;
        fromhere -= 236 + 4;
@@ -224,9 +262,9 @@ netin_DHCP4_sel:
                        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;
+                       case 2: return (intptr_t) netreply_dhcp4_offer;
+                       case 5: return (intptr_t) netdb_dhcp4_ack;
+                       case 6: return (intptr_t) netdb_dhcp4_nak;
                        default: return NULL;
                        }
                default:
@@ -246,7 +284,7 @@ netin_6BED4_sel:
 netin_IP6_sel:
        if ((get08 (0) & 0xf0) != 0x60) return NULL;
        store (MEM_IP6_HEAD, struct ip6_hdr);
-       uint8_t ip6_nxthdr = get08 (6);
+       ip6_nxthdr = get08 (6);
        forward (struct ip6_hdr);
        store (MEM_IP6_PLOAD, uint8_t);
        //
@@ -261,13 +299,13 @@ netin_IP6_sel:
        // Hande incoming ICMP6 traffic
 netin_ICMP6_sel:
        store (MEM_ICMP6_HEAD, struct icmp6_hdr);
-       uint16_t icmp6_type_code = get16 (0);
+       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_ROUTER_ADVERT << 8:     return (fromhere < 16)? NULL: (intptr_t) netdb_router_advertised;
+       case ND_NEIGHBOR_SOLICIT << 8:  return (fromhere < 24)? NULL: (intptr_t) netreply_icmp6_ngb_disc;
+       case ND_NEIGHBOR_ADVERT << 8:   return (fromhere < 24)? NULL: (intptr_t) 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_REQUEST << 8:   return (fromhere <  8)? NULL: (intptr_t) netreply_icmp6_echo_req;
        case ICMP6_ECHO_REPLY << 8:     return (fromhere <  8)? NULL: NULL; /* Future option */
        default: return NULL;
        }
@@ -276,9 +314,9 @@ netin_ICMP6_sel:
        // 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);
+       mem [MEM_UDP6_PLOAD] = (intptr_t) (here + sizeof (struct udphdr));
+       udp6_src = mem [MEM_UDP6_SRC_PORT] = get16 (0);
+       udp6_dst = mem [MEM_UDP6_DST_PORT] = get16 (2);
        here += sizeof (struct udphdr);
        //
        // Port mapping:
@@ -289,14 +327,14 @@ netin_UDP6_sel:
        // udp6_dst == 53     is DNS
        if (udp6_dst >= 0x4000) {
                if (udp6_dst & 0x0001) {
-                       mem [MEM_RTP_HEAD] = here;
-                       return net_rtp;
+                       mem [MEM_RTP_HEAD] = (intptr_t) here;
+                       return (intptr_t) net_rtp;
                } else {
-                       return net_rtcp;
+                       return (intptr_t) net_rtcp;
                }
        } else if (udp6_dst == 5060) {
-               mem [MEM_SIP_HEAD] = here;
-               return net_sip;
+               mem [MEM_SIP_HEAD] = (intptr_t) here;
+               return (intptr_t) net_sip;
        } else if (udp6_dst == 5353) {
                goto netin_DNSSD_sel;
        } else if (udp6_dst == 53) {
@@ -310,11 +348,11 @@ netin_UDP6_sel:
 
 netin_DHCP6_sel:
        store (MEM_DHCP6_HEAD, uint8_t);
-       uint8_t dhcp6_tag = *here;
+       dhcp6_tag = *here;
        switch (dhcp6_tag) {
-       case 2: return netreply_dhcp6_advertise;
-       case 7: return netdb_dhcp6_reply;
-       case 10: return netdb_dhcp6_reconfigure;
+       case 2: return (intptr_t) netreply_dhcp6_advertise;
+       case 7: return (intptr_t) netdb_dhcp6_reply;
+       case 10: return (intptr_t) netdb_dhcp6_reconfigure;
        default: return NULL;
        }
 
@@ -324,22 +362,22 @@ netin_DNS_sel:
 
 netin_DNSSD_sel:
        store (MEM_DNSSD_HEAD, uint8_t);
-       uint16_t dnssd_flags = get16 (2);
+       dnssd_flags = get16 (2);
        if (dnssd_flags & 0x8000) {
                // Response
                if (dnssd_flags & 0x0203) {
-                       return net_mdns_resp_error;
+                       return (intptr_t) net_mdns_resp_error;
                } else if (dnssd_flags & 0x0400) {
-                       return net_mdns_resp_dyn;
+                       return (intptr_t) net_mdns_resp_dyn;
                } else {
-                       return net_mdns_query_ok;
+                       return (intptr_t) net_mdns_query_ok;
                }
        } else {
                // Query
                if ((dnssd_flags ^ 0x2000) & 0x3c00) {
-                       return net_mdns_query_error;
+                       return (intptr_t) net_mdns_query_error;
                } else {
-                       return net_mdns_query_ok;
+                       return (intptr_t) net_mdns_query_ok;
                }
        }
 
diff --git a/src/net/llconly.c b/src/net/llconly.c
new file mode 100644 (file)
index 0000000..743c006
--- /dev/null
@@ -0,0 +1,225 @@
+/* llconly.c -- Network functions covering LLC only.
+ *
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This mini network stack is designed for very simple targets,
+ * such as network testing or a bootloader.  It only supports
+ * IEEE 802.2, that is, LLC.  And it even does a fairly modest
+ * job at that.
+ *
+ * This code is suitable for running a network console over LLC2
+ * and for running TFTP over LLC1.  It was not designed with any
+ * higher purpose in mind.  It is not designed to integrate with
+ * a more complete network stack like the phone application's.
+ * Hence the name llconly.c!
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include <config.h>
+
+#include <0cpm/cons.h>
+
+
+
+/* Send a reply through LLC1.
+ * The packet provided have the responded-to MAC/LLC SAPs.
+ * The packet size is completed with any reply content.
+ * This routine updates MAC addresses and LLC headers.
+ */
+void netreply_llc1 (uint8_t *pkt, uint16_t pktlen) {
+       uint8_t tmp;
+       memcpy (pkt +  0, pkt + 6, 6);
+       memcpy (pkt +  6, "\x00\x0b\x82\x19\xa0\xf4", 6);
+       pkt [12] = (pktlen - 12 - 2) >> 8;
+       pkt [13] = (pktlen - 12 - 2) & 0xff;
+       tmp = pkt [14];
+       pkt [14] = pkt [15];
+       pkt [15] = tmp; // Command flag -- LLC1 only uses commands
+       // Send and forget -- LLC1 is not guaranteed delivery
+       bottom_network_send (pkt, pktlen);
+}
+
+
+static bool llc_connected = false;
+static uint8_t peer_sap;
+static uint8_t peer_mac [6];
+static uint8_t llc_ua [6 + 6 + 2 + 3];
+static uint8_t llc_rr [6 + 6 + 2 + 4];
+static uint8_t llc_sent;
+static uint8_t llc_received;
+static uint8_t llc_input;
+
+
+/* Dummy LLC2 send routine, ignoring "cnx" as there is just one LLC2 connection.
+ * Before sending, the routine will first establish whether the last send
+ * was successful; if not, it will repeat that.  The return value is true if at
+ * least the new send was done, relying on future calls to resend if need be.
+ */
+uint8_t llc_pkt [100];
+uint16_t llc_pktlen;
+bool netsend_llc2 (struct llc2 *cnx, uint8_t *data, uint16_t datalen) {
+       bool newpkt;
+       if (datalen > 80) {
+               return false;
+       }
+       if (!llc_connected) {
+               return false;
+       }
+       newpkt = (llc_sent == llc_received);
+       if (newpkt) {
+               // Sending is complete, construct new packet as requested
+               memcpy (llc_pkt +  0, peer_mac, 6);
+               memcpy (llc_pkt +  6, "\x00\x0b\x82\x19\xa0\xf4", 6);
+               llc_pkt [12] = 0x00;
+               llc_pkt [13] = datalen + 4;
+               llc_pkt [14] = peer_sap;                // DSAP
+               llc_pkt [15] = 20;                      // SSAP
+               llc_pkt [16] = llc_sent << 1;           // N(S) = 0x00, information frame
+               llc_pkt [17] = llc_input << 1;          // N(R) = sent-up-to-here, low bit reset
+               memcpy (llc_pkt + 18, data, datalen);
+               llc_pktlen = 6 + 6 + 2 + 4 + datalen;
+               llc_sent++;
+               llc_sent &= 0x7f;
+       }
+       bottom_network_send (llc_pkt, llc_pktlen);
+       return newpkt;
+}
+
+struct llc2 {
+       uint8_t dummy;
+};
+static struct llc2 llc2_dummy_handle;
+
+/* LLC-only network packet handling, specifically for:
+ *  - LLC2 console at SAP 20
+ *  - LLC1 firmware access through TFTP at SAP 68
+ */
+void nethandler_llconly (uint8_t *pkt, uint16_t pktlen) {
+       uint16_t typelen;
+       uint16_t cmd;
+       bool ack = false;
+       bool type1;
+       typelen = (pkt [12] << 8) | pkt [13];
+#if 0
+       if ((pktlen < 14) || (typelen < 46)) {
+#ifdef CONFIG_DEVEL
+               bottom_printf ("Unpadded packet length %d received\n", pktlen);
+#endif
+               return;
+       }
+#endif
+       if (typelen > 1500) {
+#ifdef CONFIG_DEVEL
+               bottom_printf ("Traffic is not LLC but protocol 0x%4x\n", typelen);
+#endif
+               return;
+       }
+       if ((typelen > 64) && (typelen != pktlen - 14)) {
+#ifdef CONFIG_DEVEL
+               bottom_printf ("Illegal length %d received (pktlen = %d)\n", typelen, pktlen);
+#endif
+               return;
+       }
+#if 0
+       if (pkt [14] != 20) {
+#ifdef CONFIG_DEVEL
+               bottom_printf ("Received LLC traffic for SAP %d instead of 20\n", pkt [14]);
+#endif
+               return;
+       }
+#endif
+       cmd = pkt [16];
+       type1 = (cmd & 0x03) == 0x03;
+       if (!type1) {
+               cmd |= pkt [17] << 8;
+       }
+       if (llc_connected && !type1) {
+               if (memcmp (pkt + 6, peer_mac, 6) != 0) {
+                       // Peer MAC should be the constant while connected
+                       return;
+               }
+               if ((pkt [15] & 0xfe) != peer_sap) {
+                       // Peer SAP should be constant while connected
+                       return;
+               }
+       }
+       if (cmd == 0x03) {                              // UI (llc.datagram)
+#ifdef CONFIG_FUNCTION_FIRMWARE_UPGRADES
+               if (pkt [14] == 68) {
+                       void bootloader_datagram (uint8_t *pkt, uint16_t pktlen);
+                       bootloader_datagram (pkt, pktlen);
+               } else {
+#ifdef CONFIG_DEVEL
+                       bottom_printf ("LLC1 UA is only used for TFTP, use SAP 68 and not %d\n", pkt [14]);
+#endif
+               }
+#else
+#ifdef CONFIG_DEVEL
+               bottom_printf ("No bootloader -- ignoring TFTP over LLC1\n");
+#endif
+       } else if (pkt [14] != 20) {
+#ifdef CONFIG_DEVEL
+               bottom_printf ("To access the network console, use SAP 20 and not %d\n", pkt [14]);
+#endif
+#endif
+       } else if (cmd == 0x7f) {                       // SABME (llc.connect)
+               memcpy (peer_mac, pkt + 6, 6);
+               peer_sap = pkt [15] & 0xfe;
+               llc_sent = llc_received = llc_input = 0x00;
+               llc_connected = true;
+               netcons_connect (&llc2_dummy_handle);
+               ack = true;
+       } else if (cmd == 0x53) {                       // DISC  (llc.disconnect)
+               llc_connected = false;
+               netcons_close ();
+               ack = true;
+       } else if (cmd == 0x87) {                       // FRMR (llc.framereject)
+               llc_received = llc_sent;
+       } else if ((cmd & 0x0001) == 0x0000) {          // Data sent back (will be ignored)
+               memcpy (llc_rr +  0, peer_mac, 6);
+               memcpy (llc_rr +  6, "\x00\x0b\x82\x19\xa0\xf4", 6);
+                memcpy (llc_rr + 12, "\x00\x04\x00\x15", 4);
+               llc_rr [14] = peer_sap;
+               llc_rr [16] = 0x01;                     // supervisory, RR
+               llc_rr [17] = (cmd + 2) & 0xfe;         // outgoing N(R) = incoming N(S) + 1
+               bottom_network_send (llc_rr, sizeof (llc_rr));
+       } else if ((cmd & 0x0007) == 0x0001) {          // Receiver ready / Receiver Reject
+               llc_received = (cmd >> 9);
+       } else {
+#ifdef CONFIG_DEVEL
+               bottom_printf ("Selfishly ignoring LLC traffic with cmd bytes 0x%2x%2x\n",
+                                       (uint16_t) pkt [16], (uint16_t) pkt [17]);
+#endif
+       }
+       if (ack) {
+               memcpy (llc_ua +  0, peer_mac, 6);
+               memcpy (llc_ua +  6, "\x00\x0b\x82\x19\xa0\xf4", 6);
+               memcpy (llc_ua + 12, "\x00\x03\x00\x15\x73", 5);
+               llc_ua [14] = peer_sap;
+               // Try sending; assume repeat will be caused by other/smarter side
+               bottom_network_send (llc_ua, sizeof (llc_ua));
+       }
+}
+
index aff0eb6..a965321 100644 (file)
@@ -1,24 +1,44 @@
 /* netreply.c -- Directly responding to parsed packets
  *
- * From: Rick van Rein <rick@openfortress.nl>
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
+#include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <stdarg.h>
 
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <netinet/ip6.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/icmp6.h>
-#include <netinet/if_ether.h>
+// #include <netinet/ip.h>
+// #include <netinet/udp.h>
+// #include <netinet/ip6.h>
+// #include <netinet/ip_icmp.h>
+// #include <netinet/icmp6.h>
+// #include <netinet/if_ether.h>
 
 #include <config.h>
 
 #include <0cpm/cpu.h>
+#include <0cpm/irq.h>
+#include <0cpm/timer.h>
+#include <0cpm/netinet.h>
 #include <0cpm/netfun.h>
 #include <0cpm/netdb.h>
+#include <0cpm/cons.h>
 
 
 /* A few well-known addresses to look for
@@ -32,7 +52,8 @@ uint8_t ip4_mine [4] = { 192, 168, 3, 13 };
 
 extern uint8_t linklocal_mine [];
 
-uint8_t ether_mine [ETHER_ADDR_LEN] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; 
+//TODO:MAC_FROM_BOTTOM// uint8_t ether_mine [ETHER_ADDR_LEN] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; 
+uint8_t ether_mine [ETHER_ADDR_LEN] = { 0x00, 0x0b, 0x82, 0x19, 0xa0, 0xf4 }; 
 
 uint16_t bootsecs = 0;
 
@@ -62,16 +83,17 @@ uint8_t *netreply_ether (uint8_t *pout, intptr_t *mem) {
  * Some IPv4 fields are filled later: protocol, tot_len, check.
  */
 uint8_t *netreply_ip4 (uint8_t *pout, intptr_t *mem) {
+       struct iphdr *ip4in;
+       struct iphdr *ip4out;
        pout = netreply_ether (pout, mem);
-       struct iphdr *ip4in  = (struct iphdr *) mem [MEM_IP4_HEAD];
-       struct iphdr *ip4out = (struct iphdr *) pout;
+       ip4in  = (struct iphdr *) mem [MEM_IP4_HEAD];
+       ip4out = (struct iphdr *) pout;
        bzero (ip4out, sizeof (struct iphdr));
-       ip4out->version = 4;
-       ip4out->ihl = 5;
-       ip4out->ttl = 64;
-       ip4out->frag_off = htons (0x4000);      // Don't fragment
-       ip4out->saddr = ip4in->daddr;
-       ip4out->daddr = ip4in->saddr;
+       netset8  (ip4out->version_ihl, 0x45);
+       netset8  (ip4out->ttl, 64);
+       netset16 (ip4out->frag_off, 0x4000);    // Don't fragment
+       memcpy (&ip4out->saddr, &ip4in->daddr, 4);
+       memcpy (&ip4out->daddr, &ip4in->saddr, 4);
        mem [MEM_IP4_HEAD] = (uintptr_t) ip4out;
        return &pout [sizeof (struct iphdr)];
 }
@@ -80,10 +102,11 @@ uint8_t *netreply_ip4 (uint8_t *pout, intptr_t *mem) {
  * Some fields are filled later: len, check.
  */
 uint8_t *netreply_udp4 (uint8_t *pout, intptr_t *mem) {
+       struct udphdr *udp;
        pout = netreply_ip4 (pout, mem);
-       struct udphdr *udp = (struct udphdr *) pout;
-       udp->source = htons (mem [MEM_UDP4_DST_PORT]);
-       udp->dest   = htons (mem [MEM_UDP4_SRC_PORT]);
+       udp = (struct udphdr *) pout;
+       netset16 (udp->source, mem [MEM_UDP4_DST_PORT]);
+       netset16 (udp->dest  , mem [MEM_UDP4_SRC_PORT]);
        mem [MEM_UDP4_HEAD] = (intptr_t) udp;
        return &pout [sizeof (struct udphdr)];
 }
@@ -92,11 +115,12 @@ uint8_t *netreply_udp4 (uint8_t *pout, intptr_t *mem) {
  * Some fields are filled later: len, check.
  */
 uint8_t *netreply_udp4_6bed4 (uint8_t *pout, intptr_t *mem) {
-       mem [MEM_IP4_SRC] = htonl (ip4_6bed4);
+       struct udphdr *udp;
+       mem [MEM_IP4_SRC] = htonl (ip4_6bed4);  // TODO -- netset16?
        pout = netreply_ip4 (pout, mem);
-       struct udphdr *udp = (struct udphdr *) pout;
-       udp->source = htons (mem [MEM_UDP4_DST_PORT]);
-       udp->dest   = htons (3653);
+       udp = (struct udphdr *) pout;
+       netset16 (udp->source, mem [MEM_UDP4_DST_PORT]);
+       netset16 (udp->dest  , 3653);
        mem [MEM_6BED4_PLOAD] =
        mem [MEM_UDP4_HEAD] = (intptr_t) udp;
        return &pout [sizeof (struct udphdr)];
@@ -107,6 +131,7 @@ uint8_t *netreply_udp4_6bed4 (uint8_t *pout, intptr_t *mem) {
  */
 uint8_t *netreply_ip6 (uint8_t *pout, intptr_t *mem) {
        struct ip6_hdr *in6 = (struct ip6_hdr *) mem [MEM_IP6_HEAD];
+       struct ip6_hdr *ip6;
        if (mem [MEM_6BED4_PLOAD] != 0) {
                // Use 6bed4 for destination address
                pout = netreply_udp4_6bed4 (pout, mem);
@@ -114,9 +139,9 @@ uint8_t *netreply_ip6 (uint8_t *pout, intptr_t *mem) {
                // Use LAN for destination address
                pout = netreply_ether (pout, mem);
        }
-       struct ip6_hdr *ip6 = (struct ip6_hdr *) pout;
-       ip6->ip6_vfc = htonl (0x60000000);
-       ip6->ip6_hlim = 64;
+       ip6 = (struct ip6_hdr *) pout;
+       netset32 (ip6->ip6_flow, 0x60000000);
+       netset8  (ip6->ip6_hlim, 64);
        memcpy (&ip6->ip6_src, &in6->ip6_dst, 16);
        memcpy (&ip6->ip6_dst, &in6->ip6_src, 16);
        mem [MEM_IP6_HEAD] = (intptr_t) ip6;
@@ -127,10 +152,11 @@ uint8_t *netreply_ip6 (uint8_t *pout, intptr_t *mem) {
  * Some fields are filled later: len, check.
  */
 uint8_t *netreply_udp6 (uint8_t *pout, intptr_t *mem) {
+       struct udphdr *udp;
        pout = netreply_ip6 (pout, mem);
-       struct udphdr *udp = (struct udphdr *) pout;
-       udp->source = htons (mem [MEM_UDP6_DST_PORT]);
-       udp->dest   = htons (mem [MEM_UDP6_SRC_PORT]);
+       udp = (struct udphdr *) pout;
+       netset16 (udp->source, mem [MEM_UDP6_DST_PORT]);
+       netset16 (udp->dest  , mem [MEM_UDP6_SRC_PORT]);
        mem [MEM_UDP6_HEAD] = (intptr_t) udp;
        return &pout [sizeof (struct udphdr)];
 }
@@ -143,19 +169,23 @@ uint8_t *netreply_udp6 (uint8_t *pout, intptr_t *mem) {
  * There are no checksum or length fields in ARP.
  */
 uint8_t *netreply_arp_query (uint8_t *pout, intptr_t *mem) {
-       printf ("Received an ARP Request; replying\n");
+       struct ether_arp *arpout;
+       struct ether_arp *arpin;
+       bottom_printf ("Received an ARP Request; replying\n");
        pout = netreply_ether (pout, mem);
-       struct ether_arp *arpout  = (struct ether_arp *) pout;
-       struct ether_arp *arpin  = (struct ether_arp *) mem [MEM_ARP_HEAD];
-       if (memcmp (arpin->arp_tpa, ip4_mine, 4) == 0) {
+       arpout = (struct ether_arp *) pout;
+       arpin  = (struct ether_arp *) mem [MEM_ARP_HEAD];
+       //TODO:OLD// if (memcmp (arpin->arp_tpa, ip4_mine, 4) == 0) {
+       // TODO: Real binding for IPv4
+       if (netget32 (*(nint32_t *)arpin->arp_tpa) == ip4binding [0].ip4addr) {
                // arpout->ea_hdr.ar_hrd = htons (ARPHRD_IEEE802);
-               arpout->ea_hdr.ar_hrd = htons (ARPHRD_ETHER);
-               arpout->ea_hdr.ar_pro = htons (ETHERTYPE_IP);
-               arpout->ea_hdr.ar_hln = ETHER_ADDR_LEN;
-               arpout->ea_hdr.ar_pln = 4;              // IPv4 len
-               arpout->ea_hdr.ar_op  = htons (2);      // ARP Reply
+               netset16 (arpout->ea_hdr.ar_hrd, ARPHRD_ETHER);
+               netset16 (arpout->ea_hdr.ar_pro, ETHERTYPE_IP);
+               netset8  (arpout->ea_hdr.ar_hln, ETHER_ADDR_LEN);
+               netset8  (arpout->ea_hdr.ar_pln, 4);    // IPv4 len
+               netset16 (arpout->ea_hdr.ar_op,  2);    // ARP Reply
                memcpy (arpout->arp_sha, ether_mine, ETHER_ADDR_LEN);
-               memcpy (arpout->arp_spa, ip4_mine, 4);
+               netset32 (*(nint32_t *)arpout->arp_spa, mem [MEM_IP4_DST]);
                memcpy (arpout->arp_tha, arpin->arp_sha, ETHER_ADDR_LEN);
                memcpy (arpout->arp_tpa, arpin->arp_spa, 4);
                return pout + sizeof (struct ether_arp);
@@ -168,18 +198,21 @@ uint8_t *netreply_arp_query (uint8_t *pout, intptr_t *mem) {
  * Some fields are filled later: icmp_cksum.
  */
 uint8_t *netreply_icmp4_echo_req (uint8_t *pout, intptr_t *mem) {
-       printf ("Received an ICMPv4 Echo Request; replying\n");
+       struct icmphdr *icmp4out;
+       struct icmphdr *icmp4in;
+       uint32_t alen;
+       bottom_printf ("Received an ICMPv4 Echo Request; replying\n");
        pout = netreply_ip4 (pout, mem);
-       struct icmphdr *icmp4out = (struct icmphdr *) pout;
-       struct icmphdr *icmp4in  = (struct icmphdr *) mem [MEM_ICMP4_HEAD];
-       icmp4out->type = ICMP_ECHOREPLY;
-       icmp4out->code = 0;
-       icmp4out->un.echo.id       = icmp4in->un.echo.id ;
+       icmp4out = (struct icmphdr *) pout;
+       icmp4in  = (struct icmphdr *) mem [MEM_ICMP4_HEAD];
+       netset8  (icmp4out->type, ICMP_ECHOREPLY);
+       netset8  (icmp4out->code, 0);
+       icmp4out->un.echo.id = icmp4in->un.echo.id;
        icmp4out->un.echo.sequence = icmp4in->un.echo.sequence;
        pout = pout + sizeof (struct icmphdr);
-       uint32_t alen = mem [MEM_ALL_DONE] - mem [MEM_ICMP4_HEAD] - sizeof (struct icmphdr);
+       alen = mem [MEM_ALL_DONE] - mem [MEM_ICMP4_HEAD] - sizeof (struct icmphdr);
        if ((alen > 0) && (alen < 128)) {
-               memcpy (&icmp4out [1], &icmp4in [1], alen);
+               memcpy (icmp4out + 1, icmp4in + 1, alen);
                pout += alen;
        }
        mem [MEM_ICMP4_HEAD] = (intptr_t) icmp4out;
@@ -190,12 +223,14 @@ uint8_t *netreply_icmp4_echo_req (uint8_t *pout, intptr_t *mem) {
  * Some fields are filled later: icmp6_cksum.
  */
 uint8_t *netreply_icmp6_echo_req (uint8_t *pout, intptr_t *mem) {
-       printf ("Received an ICMPv6 Echo Request; replying\n");
+       struct icmp6_hdr *icmp6;
+       uint16_t len;
+       bottom_printf ("Received an ICMPv6 Echo Request; replying\n");
        pout = netreply_ip6 (pout, mem);
-       struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) pout;
-       icmp6->icmp6_type = ICMP6_ECHO_REPLY;
-       icmp6->icmp6_code = 0;
-       uint16_t len = mem [MEM_ALL_DONE] - mem [MEM_ICMP6_HEAD];
+       icmp6 = (struct icmp6_hdr *) pout;
+       netset8 (icmp6->icmp6_type, ICMP6_ECHO_REPLY);
+       netset8 (icmp6->icmp6_code, 0);
+       len = mem [MEM_ALL_DONE] - mem [MEM_ICMP6_HEAD];
        memcpy (&icmp6->icmp6_data8,
                        (void *) (mem [MEM_ICMP6_HEAD] + 4),
                        len - 4);
@@ -210,13 +245,20 @@ uint8_t *netreply_icmp6_echo_req (uint8_t *pout, intptr_t *mem) {
  * Some fields are filled later: icmp6_cksum.
  */
 uint8_t *netreply_icmp6_ngb_disc (uint8_t *pout, intptr_t *mem) {
-       printf ("Received an ICMPv6 Neighbour Discovery; replying\n");
-       int bndidx = IP6BINDING_COUNT;
-       uint8_t *addr = linklocal_mine;
-       uint16_t flgs = 0;
+       int bndidx;
+       uint8_t *addr;
+       uint16_t flgs;
+       struct ip6_hdr *ip6;
+       struct icmp6_hdr *icmp6;
+       bottom_printf ("Received an ICMPv6 Neighbour Discovery; replying\n");
+       // The first comparison is against the link local address fe80::...
+       bndidx = IP6BINDING_COUNT;
+       addr = linklocal_mine;
+       flgs = I6B_DEFEND_ME;
        do {
-               if ((flgs & (I6B_EXPIRED | I6B_TENTATIVE)) == 0) {
+               if ((flgs & (I6B_EXPIRED | I6B_DEFEND_ME)) == I6B_DEFEND_ME) {
                        if (memcmp ((void *) (mem [MEM_ICMP6_HEAD] + 8), addr, 16) == 0) {
+                               bndidx++;
                                break;
                        }
                }
@@ -227,16 +269,16 @@ uint8_t *netreply_icmp6_ngb_disc (uint8_t *pout, intptr_t *mem) {
                return NULL;
        }
        pout = netreply_ip6 (pout, mem);
-       struct ip6_hdr *ip6 = (struct ip6_hdr *) mem [MEM_IP6_HEAD];
+       ip6 = (struct ip6_hdr *) mem [MEM_IP6_HEAD];
        memcpy (&ip6->ip6_src, addr, 16);
-       ip6->ip6_hlim = 255;
-       struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) pout;
-       icmp6->icmp6_type = ND_NEIGHBOR_ADVERT;
-       icmp6->icmp6_code = 0;
-       icmp6->icmp6_data32 [0] = htonl (0x60000000);
+       netset8 (ip6->ip6_hlim, 255);
+       icmp6 = (struct icmp6_hdr *) pout;
+       netset8 (icmp6->icmp6_type, ND_NEIGHBOR_ADVERT);
+       netset8 (icmp6->icmp6_code, 0);
+       netset32 (icmp6->icmp6_data32 [0], 0x60000000);
        memcpy (&icmp6->icmp6_data32 [1], addr, 16);
-       icmp6->icmp6_data8 [20] = ND_OPT_TARGET_LINKADDR;
-       icmp6->icmp6_data8 [21] = 1;    // 1x 8 bytes
+       netset8 (icmp6->icmp6_data8 [20], ND_OPT_TARGET_LINKADDR);
+       netset8 (icmp6->icmp6_data8 [21], 1);   // 1x 8 bytes
        memcpy (icmp6->icmp6_data8 + 22, ether_mine, ETHER_ADDR_LEN);
        mem [MEM_ICMP6_HEAD] = (intptr_t) icmp6;
        return pout + 8 + 16 + 8;
@@ -248,18 +290,27 @@ uint8_t *netreply_icmp6_ngb_disc (uint8_t *pout, intptr_t *mem) {
  */
 uint8_t *netreply_dhcp4_offer (uint8_t *pout, intptr_t *mem) {
        uint8_t *yiaddrptr = (uint8_t *) (mem [MEM_DHCP4_HEAD] + 16);
-       printf ("DHCPv4 offer for %d.%d.%d.%d received -- requesting its activation\n", (int) yiaddrptr [0], (int) yiaddrptr [1], (int) yiaddrptr [2], (int) yiaddrptr [3]);
+       uint8_t *popt;
+       static const uint8_t dhcp4_options [] = {
+               99, 130, 83, 99,        // Magic cookie, RFC 1497
+               53, 1, 3,               // DHCP message type REQUEST
+               50, 4, 0, 0, 0, 0,      // Requested IP @ 4 + 3 + 2
+               // 55, 4, 1, 3, 42, 2,  // Param Request List:
+                                       // mask, router, ntp?, time offset?.
+               255                     // End Option
+       };
+       bottom_printf ("DHCPv4 offer for %d.%d.%d.%d received -- requesting its activation\n", (int) yiaddrptr [0], (int) yiaddrptr [1], (int) yiaddrptr [2], (int) yiaddrptr [3]);
        // TODO: Validate offer to be mine
        mem [MEM_ETHER_DST] = (intptr_t) ether_broadcast;
        pout = netreply_udp4 (pout, mem);
-       ((struct iphdr *) mem [MEM_IP4_HEAD])->daddr = 0xffffffff;
+       netset32 (((struct iphdr *) mem [MEM_IP4_HEAD])->daddr, 0xffffffff);
        bzero (pout, 576);      // erase the acceptable package size
        pout [0] = 1;           // bootrequest
        pout [1] = 1;           // ARP hardware address type
        pout [2] = 6;           // ARP hardware address length
        pout [3] = 0;           // hops
        memcpy (pout + 4, ether_mine + 2, 4);           // client-randomiser
-       *(uint16_t *) (pout +  8) = htons (bootsecs++); // 0 or seconds trying
+       *(uint16_t *) (pout +  8) = htons (bootsecs++); // 0 or seconds trying -- TODO:netset16
        // flags=0, no broadcast reply needed
        // ciaddr [4] is 0.0.0.0, the initial client address
        // yiaddr [4] is 0.0.0.0, the "your" address
@@ -269,15 +320,7 @@ uint8_t *netreply_dhcp4_offer (uint8_t *pout, intptr_t *mem) {
        // sname [64], the server hostname is empty
        // file [128], the boot filename, is empty
        // options
-       uint8_t *popt = pout + 236;
-       static const uint8_t dhcp4_options [] = {
-               99, 130, 83, 99,        // Magic cookie, RFC 1497
-               53, 1, 3,               // DHCP message type REQUEST
-               50, 4, 0, 0, 0, 0,      // Requested IP @ 4 + 3 + 2
-               // 55, 4, 1, 3, 42, 2,  // Param Request List:
-                                       // mask, router, ntp?, time offset?.
-               255                     // End Option
-       };
+       popt = pout + 236;
        memcpy (popt, dhcp4_options, sizeof (dhcp4_options));
        memcpy (popt + 4 + 3 + 2, yiaddrptr, 4);
        // return popt + sizeof (dhcp4_options);
@@ -292,18 +335,22 @@ uint8_t *netreply_dhcp4_offer (uint8_t *pout, intptr_t *mem) {
  * will actually take hold of all the IPv6 space that it can get.
  */
 uint8_t *netreply_dhcp6_advertise (uint8_t *pout, intptr_t *mem) {
-       printf ("DHCPv6 advertisement\n");
+       uint32_t adlen;
+       struct udphdr *udp;
+       nint16_t *options;
+       bottom_printf ("DHCPv6 advertisement\n");
        // TODO: Validate offer to be mine
-       uint32_t adlen = mem [MEM_ALL_DONE] - mem [MEM_DHCP6_HEAD];
+       adlen = mem [MEM_ALL_DONE] - mem [MEM_DHCP6_HEAD];
        if (adlen > 1024) {
                return NULL;    // Suspicuously long options
        }
        pout = netreply_udp6 (pout, mem);
-       struct udphdr *udp = (struct udphdr *) mem [MEM_UDP6_HEAD];
-       udp->dest = htons (547);
+       udp = (struct udphdr *) mem [MEM_UDP6_HEAD];
+       netset16 (udp->dest, 547);
        memcpy (pout, (void *) mem [MEM_DHCP6_HEAD], adlen);
-       pout [0] = 3;
        mem [MEM_DHCP6_HEAD] = (intptr_t) pout;
+       netdb_dhcp6_recurse_options ((nint16_t *) (pout + 4), adlen - 4);
+       pout [0] = 3;
        return pout + adlen;
 }
 
index 4fcf4c5..5a26bd4 100644 (file)
@@ -1,6 +1,24 @@
 /* netsend.c -- Initiatiating interactions by composing new packets
  *
- * This set of routines is used to build network packets from scratch.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* This set of routines is used to build network packets from scratch.
  * Only really small actions will be handled by immediate netreply_
  * routines, but many others will need some internal processing first.
  *
 
 #include <string.h>
 
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#include <netinet/if_ether.h>
+// #include <netinet/ip.h>
+// #include <netinet/udp.h>
+// #include <netinet/ip6.h>
+// #include <netinet/icmp6.h>
+// #include <netinet/if_ether.h>
 
 #include <config.h>
 
 #include <0cpm/cpu.h>
+#include <0cpm/irq.h>
+#include <0cpm/timer.h>
+#include <0cpm/netinet.h>
 #include <0cpm/netfun.h>
 #include <0cpm/netdb.h>
 
@@ -36,7 +57,7 @@ extern uint8_t ether_mine [];
 
 extern uint32_t ip4_6bed4;
 
-uint8_t ether_broadcast [ETHER_ADDR_LEN] = {
+const uint8_t ether_broadcast [ETHER_ADDR_LEN] = {
                                0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 uint8_t ether_multicast_all_dhcp6_servers [ETHER_ADDR_LEN] = {
@@ -44,7 +65,8 @@ uint8_t ether_multicast_all_dhcp6_servers [ETHER_ADDR_LEN] = {
 
 uint8_t linklocal_mine [] = {
        0xfe, 0x80, 0, 0, 0, 0, 0, 0,
-       0x13, 0x22, 0x33, 0xff, 0xfe, 0x44, 0x55, 0x66 };
+       //TODO:MAC_FROM_BOTTOM// 0x13, 0x22, 0x33, 0xff, 0xfe, 0x44, 0x55, 0x66 };
+       0x02, 0x0b, 0x82, 0xff, 0xfe, 0x19, 0xa0, 0xf4 };
 
 uint8_t allnodes_linklocal_address [] = {
         0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x01 };
@@ -53,10 +75,12 @@ uint8_t allrouters_linklocal_address [] = {
         0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x02 };
 
 struct ip6binding binding_linklocal [1] = { {
+       { { NULL, NULL, 0 }, NULL, TIME_MSEC(0) },
        NULL,
        // 2 lines -- copy of linklocal_mine above:
        { 0xfe, 0x80, 0, 0, 0, 0, 0, 0,
-         0x13, 0x22, 0x33, 0xff, 0xfe, 0x44, 0x55, 0x66 },
+       //TODO:MAC_FROM_BOTTOM//   0x13, 0x22, 0x33, 0xff, 0xfe, 0x44, 0x55, 0x66 },
+         0x02, 0x0b, 0x82, 0xff, 0xfe, 0x19, 0xa0, 0xf4 },
        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        0xffffffff,
        NULL,
@@ -109,15 +133,15 @@ uint8_t *netsend_ether (uint8_t *pout, intptr_t *mem) {
  * Some IPv4 fields are filled later: protocol, tot_len, check.
  */
 uint8_t *netsend_ip4 (uint8_t *pout, intptr_t *mem) {
+       struct iphdr *ip4;
        pout = netsend_ether (pout, mem);
-       struct iphdr *ip4 = (struct iphdr *) pout;
+       ip4 = (struct iphdr *) pout;
        bzero (ip4, sizeof (struct iphdr));
-       ip4->version = 4;
-       ip4->ihl = 5;
-       ip4->ttl = 64;
-       ip4->frag_off = htons (0x4000); // Don't fragment
-       ip4->saddr = htonl (mem [MEM_IP4_SRC]);
-       ip4->daddr = htonl (mem [MEM_IP4_DST]);
+       netset8  (ip4->version_ihl, 0x45);
+       netset8  (ip4->ttl, 64);
+       netset16 (ip4->frag_off, 0x4000);       // Don't fragment
+       netset32 (ip4->saddr, mem [MEM_IP4_SRC]);
+       netset32 (ip4->daddr, mem [MEM_IP4_DST]);
        mem [MEM_IP4_HEAD] = (uint32_t) ip4;
        return &pout [sizeof (struct iphdr)];
 }
@@ -126,11 +150,14 @@ uint8_t *netsend_ip4 (uint8_t *pout, intptr_t *mem) {
  * Some fields are filled later: len, check.
  */
 uint8_t *netsend_udp4 (uint8_t *pout, intptr_t *mem) {
-       // TODO: Setup MEM_ETHER_DST with router's address
+       struct udphdr *udp;
+       // TODO: Always setup MEM_ETHER_DST with router's address?
+       // struct ip6binding *bnd = (struct ip6binding *) mem [MEM_BINDING6];
+       // mem [MEM_ETHER_DST] = (intptr_t) bnd->ip4binding->ip4peermac [0];
        pout = netsend_ip4 (pout, mem);
-       struct udphdr *udp = (struct udphdr *) pout;
-       udp->source = htons (mem [MEM_UDP4_SRC_PORT]);
-       udp->dest   = htons (mem [MEM_UDP4_DST_PORT]);
+       udp = (struct udphdr *) pout;
+       netset16 (udp->source, mem [MEM_UDP4_SRC_PORT]);
+       netset16 (udp->dest  , mem [MEM_UDP4_DST_PORT]);
        mem [MEM_UDP4_HEAD] = (intptr_t) udp;
        return &pout [sizeof (struct udphdr)];
 }
@@ -140,14 +167,15 @@ uint8_t *netsend_udp4 (uint8_t *pout, intptr_t *mem) {
  */
 uint8_t *netsend_udp4_6bed4 (uint8_t *pout, intptr_t *mem) {
        struct ip6binding *bnd = (struct ip6binding *) mem [MEM_BINDING6];
+       struct udphdr *udp;
        mem [MEM_IP4_SRC] = bnd->ip4binding->ip4addr;
        mem [MEM_IP4_DST] = ip4_6bed4;
-       // TODO: Setup MEM_ETHER_DST with router's address
+       mem [MEM_ETHER_DST] = (intptr_t) bnd->ip4binding->ip4peermac [0];
        pout = netsend_ip4 (pout, mem);
-       struct udphdr *udp = (struct udphdr *) pout;
-       //TODO:dyn.ports?// udp->source = htons (bnd->ip4binding->ip4port);
-       udp->source = htons (3653);
-       udp->dest   = htons (3653);
+       udp = (struct udphdr *) pout;
+       //TODO:dyn.ports?netset16?// udp->source = htons (bnd->ip4binding->ip4port);
+       netset16 (udp->source, 3653);
+       netset16 (udp->dest  , 3653);
        mem [MEM_UDP4_HEAD] = (intptr_t) udp;
        mem [MEM_6BED4_PLOAD] = (intptr_t) (pout + sizeof (struct udphdr));
        return (uint8_t *) mem [MEM_6BED4_PLOAD];
@@ -158,17 +186,18 @@ uint8_t *netsend_udp4_6bed4 (uint8_t *pout, intptr_t *mem) {
  */
 uint8_t *netsend_ip6 (uint8_t *pout, intptr_t *mem) {
        struct ip6binding *bnd = (struct ip6binding *) mem [MEM_BINDING6];
-       if (bnd->flags & I6B_ROUTE_SOURCE_6BED4_FLAG) {
+       struct ip6_hdr *ip6;
+       if (bnd->flags & I6B_ROUTE_SOURCE_6BED4_MASK) {
                // Use 6bed4 for destination address
                pout = netsend_udp4_6bed4 (pout, mem);
        } else {
                // Use LAN for destination address
-               // TODO: Setup MEM_ETHER_DST with router's address
+               // TODO: Setup MEM_ETHER_DST with router's address?
                pout = netsend_ether (pout, mem);
        }
-       struct ip6_hdr *ip6 = (struct ip6_hdr *) pout;
-       ip6->ip6_vfc = htonl (0x60000000);
-       ip6->ip6_hlim = 64;
+       ip6 = (struct ip6_hdr *) pout;
+       netset32 (ip6->ip6_flow, 0x60000000);
+       netset8   (ip6->ip6_hlim, 64);
        memcpy (&ip6->ip6_src, bnd->ip6addr, 16);
        memcpy (&ip6->ip6_dst, (uint8_t *) mem [MEM_IP6_DST], 16);
        mem [MEM_IP6_HEAD] = (intptr_t) ip6;
@@ -179,11 +208,12 @@ uint8_t *netsend_ip6 (uint8_t *pout, intptr_t *mem) {
  * Some fields are filled later: len, check.
  */
 uint8_t *netsend_udp6 (uint8_t *pout, intptr_t *mem) {
-       // TODO: Setup MEM_ETHER_DST with router's address
+       struct udphdr *udp;
+       // 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_SRC_PORT]);
-       udp->dest   = htons (mem [MEM_UDP6_DST_PORT]);
+       udp = (struct udphdr *) pout;
+       netset16 (udp->source, mem [MEM_UDP6_SRC_PORT]);
+       netset16 (udp->dest  , mem [MEM_UDP6_DST_PORT]);
        mem [MEM_UDP6_HEAD] = (intptr_t) udp;
        return &pout [sizeof (struct udphdr)];
 }
@@ -193,12 +223,37 @@ uint8_t *netsend_udp6 (uint8_t *pout, intptr_t *mem) {
 /******************* APPLICATION LEVEL ROUTINES *******************/
 
 
+/* Create an ARP query for a local IPv4 address.
+ * The reply address for this host is in MEM_IP4_SRC.
+ * The address to send to make the request for is in MEM_IP4_DST.
+ * TODO: Consider refreshes sent only to the known MAC address.
+ */
+uint8_t *netsend_arp_query (uint8_t *pout, intptr_t *mem) {
+       struct ether_arp *arpout;
+       mem [MEM_ETHER_DST] = (intptr_t) ether_broadcast;
+       arpout = (struct ether_arp *) netsend_ether (pout, mem);
+       netset16 (arpout->ea_hdr.ar_hrd, ARPHRD_ETHER);
+       netset16 (arpout->ea_hdr.ar_pro, ETHERTYPE_IP);
+       netset8  (arpout->ea_hdr.ar_hln, ETHER_ADDR_LEN);
+       netset8  (arpout->ea_hdr.ar_pln, 4);    // IPv4 len
+       netset16 (arpout->ea_hdr.ar_op, 1);     // ARP request
+       memcpy   (arpout->arp_sha, ether_mine, ETHER_ADDR_LEN);
+       netset32 (*(nint32_t *)arpout->arp_spa, mem [MEM_IP4_SRC]);
+       bzero    (arpout->arp_tha, ETHER_ADDR_LEN);
+       netset32 (*(nint32_t *)arpout->arp_tpa, mem [MEM_IP4_DST]);
+       pout = (uint8_t *) (arpout + 1);
+       mem [MEM_ARP_HEAD] = (intptr_t) pout;
+       return pout;
+}
+
+
 /* Create an ICMPv6 Router Solicitation.
  */
 uint8_t *netsend_icmp6_router_solicit (uint8_t *pout, intptr_t *mem) {
+       struct ip6binding *bnd;
        mem [MEM_ETHER_DST] = (intptr_t) ether_broadcast;
-       struct ip6binding *bnd = (struct ip6binding *) mem [MEM_BINDING6];
-       if (bnd->flags & I6B_ROUTE_SOURCE_6BED4_FLAG) {
+       bnd = (struct ip6binding *) mem [MEM_BINDING6];
+       if (bnd->flags & I6B_ROUTE_SOURCE_6BED4_MASK) {
                // Use 6bed4 for destination address
                pout = netsend_udp4_6bed4 (pout, mem);
        } else {
@@ -219,18 +274,20 @@ uint8_t *netsend_icmp6_router_solicit (uint8_t *pout, intptr_t *mem) {
  * TODO: Set multicast target address for IPv6
  */
 uint8_t *netsend_icmp6_ngb_sol (uint8_t *pout, intptr_t *mem) {
+       struct icmp6_hdr *icmp6;
+       struct ip6binding *bnd;
        mem [MEM_ETHER_DST] = (intptr_t) ether_broadcast;
        mem [MEM_IP6_DST] = (intptr_t) ip6_multicast_all_hosts;
        pout = netsend_ip6 (pout, mem);
-       struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) pout;
-       struct ip6binding *bnd = (struct ip6binding *) mem [MEM_BINDING6];
+       icmp6 = (struct icmp6_hdr *) pout;
+       bnd = (struct ip6binding *) mem [MEM_BINDING6];
        mem [MEM_ICMP6_HEAD] = (intptr_t) pout;
-       icmp6->icmp6_type = ND_NEIGHBOR_SOLICIT;
-       icmp6->icmp6_code = 0;
-       icmp6->icmp6_data32 [0] = 0;
+       netset8  (icmp6->icmp6_type, ND_NEIGHBOR_SOLICIT);
+       netset8  (icmp6->icmp6_code, 0);
+       netset32 (icmp6->icmp6_data32 [0], 0);
        memcpy (icmp6->icmp6_data8 + 4, bnd->ip6addr, 16);
-       icmp6->icmp6_data8 [4+16+0] = 1;
-       icmp6->icmp6_data8 [4+16+1] = 1;
+       netset8 (icmp6->icmp6_data8 [4+16+0], 1);
+       netset8 (icmp6->icmp6_data8 [4+16+1], 1);
        memcpy (icmp6->icmp6_data8 + 4+16+2, ether_mine, 6);
        return pout + 24 + 8;
 }
@@ -238,6 +295,14 @@ 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) {
+       uint8_t *popt;
+       static const uint8_t dhcp4_options [] = {
+               99, 130, 83, 99,        // Magic cookie, RFC 1497
+               53, 1, 1,               // DHCP message type DISCOVER
+               55, 4, 1, 3, 42, 2,     // Param Request List:
+                                       // mask, router, ntp?, time offset?.
+               255                     // End Option
+       };
        mem [MEM_UDP4_SRC_PORT] = 68;
        mem [MEM_UDP4_DST_PORT] = 67;
        mem [MEM_IP4_DST] = 0xffffffff;
@@ -249,7 +314,7 @@ uint8_t *netsend_dhcp4_discover (uint8_t *pout, intptr_t *mem) {
        pout [2] = 6;           // ARP hardware address length
        pout [3] = 0;           // hops
        memcpy (pout + 4, ether_mine + 2, 4);           // client-randomiser
-       *(uint16_t *) (pout +  8) = htons (bootsecs++); // 0 or seconds trying
+       *(uint16_t *) (pout +  8) = htons (bootsecs++); // 0 or seconds trying -- TODO: netset16?
        // flags=0, no broadcast reply needed
        // ciaddr [4] is 0.0.0.0, the initial client address
        // yiaddr [4] is 0.0.0.0, the "your" address
@@ -259,14 +324,7 @@ uint8_t *netsend_dhcp4_discover (uint8_t *pout, intptr_t *mem) {
        // sname [64], the server hostname is empty
        // file [128], the boot filename, is empty
        // options
-       uint8_t *popt = pout + 236;
-       static const uint8_t dhcp4_options [] = {
-               99, 130, 83, 99,        // Magic cookie, RFC 1497
-               53, 1, 1,               // DHCP message type DISCOVER
-               55, 4, 1, 3, 42, 2,     // Param Request List:
-                                       // mask, router, ntp?, time offset?.
-               255                     // End Option
-       };
+       popt = pout + 236;
        memcpy (popt, dhcp4_options, sizeof (dhcp4_options));
        return popt + sizeof (dhcp4_options);
 }
@@ -274,14 +332,6 @@ 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_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;
-       pout = netsend_udp6 (pout, mem);
-       pout [0] = 1;
-       memcpy (pout + 1, ether_mine + 3, 3);
        static const uint8_t dhcp6_options [] = {
                0,1, 0,4+6,     // Client ID, ether @ 4+4 (below), etherlen 6
                        0, 3, 0, 1, 0,0,0,0,0,0,
@@ -300,6 +350,14 @@ uint8_t *netsend_dhcp6_solicit (uint8_t *pout, intptr_t *mem) {
                        0x00,0x28,0xde,0x80,    // Valid: 31d
                // 0,14, 0,0,   // Rapid Commit -- IMPOSSIBLE with IP assignmt
        };
+       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;
+       pout = netsend_udp6 (pout, mem);
+       pout [0] = 1;
+       memcpy (pout + 1, ether_mine + 3, 3);
        memcpy (pout + 4          , dhcp6_options, sizeof (dhcp6_options));
        memcpy (pout + 4 + 4+4    , ether_mine, ETHER_ADDR_LEN);
        memcpy (pout + 4 + 4+4+6+4, ether_mine, ETHER_ADDR_LEN);
index 55c5368..92d923c 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source firmware for SIP phones.
+/* Application zero -- the one that makes the phone doze off to sleep.
  *
- * Application zero -- the one that makes the phone doze off to sleep.
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index 233fc90..3c0dd58 100644 (file)
@@ -61,5 +61,17 @@ config TARGET_GIGASET
 
          TODO: Demo entry. Not implemented yet.
 
+config TARGET_IMAGINARY
+       bool "Imaginary phone targets"
+       help
+         These target phones do not actually exist.  They are merely
+         used as placeholders for hardware that is likely to come to
+         life in some shape or form in the near future.  Do not build
+         targets based on this target without updating the build
+         structures in src/target/Kconfig* and src/target/Makefile*
+         to something more concrete.
+
+         TODO: Demo entry. Not likely to build.
+
 endchoice
 
index 8dd56ad..def213e 100644 (file)
@@ -6,25 +6,31 @@ choice
 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 (READ HELP)"
        depends on TARGET_GRANDSTREAM_BT20x || TARGET_GRANDSTREAM_GXP20xx
-       default y
        help
          **Please be careful**
          The TIC55x platform is not supported by gcc or lvmm compilers.
          You can download a toolchain at no expense from the TI website,
          but this will not bring you the freedom that you need to comply
          to the GPLv3 under which the 0cpm firmerware is released.
-         Please read the file src/driver/tic55x/LICENSE-WARNING.txt about
-         the incompatibility problem between TI's toolchain and the
-         license of the 0cpm firmerware.
+         Please read the file src/driver/tic55x/LICENSE-WARNING.TXT about
+         the incompatibility problem between TI's toolchain license and
+         the open source license of the 0cpm firmerware.
+
+config PLATFORM_BLACKFIN
+       bool "Analog Devices' Blackfin"
+       depends on TARGET_IMAGINARY
+       help
+         Blackfin DSPs are Analoge Devices' systems-on-chip, supported
+         with open source toolchains based on gcc.  They are said to
+         occur in various phones.  AD suggests the U-Boot bootloader,
+         making them accessible as candidates for new firmware like this.
 
 endchoice
index 2c34970..2cbf429 100644 (file)
@@ -8,6 +8,8 @@ metavars-$(CONFIG_TARGET_LINUX_TUNTEST) += HAVE_NET_LEADER=4
 
 includes-$(CONFIG_TARGET_LINUX_TUNTEST) += bottom/linuxtuntest.h
 
+includes-$(CONFIG_DEVEL) += bottom/devel.h
+
 #
 # Platform-dependent specifics
 #
index b4ffcc5..db0c4a6 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source SIP telephony firmware.
+/* Device-specific includes for Linksys SPA962
  *
- * Device-specific includes for Linksys SPA962
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 
index f26ed78..7ac6db8 100644 (file)
@@ -1,7 +1,20 @@
-/*
- * http://devel.0cpm.org/ -- Open source SIP telephony firmware.
+/* Device-specific includes for Linksys SPA962
  *
- * Device-specific includes for Linksys SPA962
+ * This file is part of 0cpm Firmerware.
+ *
+ * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
+ *
+ * 0cpm Firmerware is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 3.
+ *
+ * 0cpm Firmerware is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
  */