r3371 - in developers/olv: . openmoko-agpsui2 openmoko-agpsui2/data openmoko-agpsui2/lto openmoko-agpsui2/lto/.deps openmoko-agpsui2/po openmoko-agpsui2/src

olv at sita.openmoko.org olv at sita.openmoko.org
Wed Nov 7 18:08:03 CET 2007


Author: olv
Date: 2007-11-07 18:07:34 +0100 (Wed, 07 Nov 2007)
New Revision: 3371

Added:
   developers/olv/openmoko-agpsui2/
   developers/olv/openmoko-agpsui2/AUTHORS
   developers/olv/openmoko-agpsui2/COPYING
   developers/olv/openmoko-agpsui2/ChangeLog
   developers/olv/openmoko-agpsui2/INSTALL
   developers/olv/openmoko-agpsui2/Makefile.am
   developers/olv/openmoko-agpsui2/NEWS
   developers/olv/openmoko-agpsui2/README
   developers/olv/openmoko-agpsui2/autogen.sh
   developers/olv/openmoko-agpsui2/configure.ac
   developers/olv/openmoko-agpsui2/data/
   developers/olv/openmoko-agpsui2/data/Makefile.am
   developers/olv/openmoko-agpsui2/data/openmoko-agpsui2.desktop
   developers/olv/openmoko-agpsui2/lto/
   developers/olv/openmoko-agpsui2/lto/.deps/
   developers/olv/openmoko-agpsui2/lto/.deps/http_error_codes.Po
   developers/olv/openmoko-agpsui2/lto/.deps/http_fetcher.Po
   developers/olv/openmoko-agpsui2/lto/.deps/lto_get.Po
   developers/olv/openmoko-agpsui2/lto/.deps/lto_util.Po
   developers/olv/openmoko-agpsui2/lto/Makefile.am
   developers/olv/openmoko-agpsui2/lto/http_error_codes.c
   developers/olv/openmoko-agpsui2/lto/http_error_codes.h
   developers/olv/openmoko-agpsui2/lto/http_fetcher.c
   developers/olv/openmoko-agpsui2/lto/http_fetcher.h
   developers/olv/openmoko-agpsui2/lto/lto_get.c
   developers/olv/openmoko-agpsui2/lto/lto_util.c
   developers/olv/openmoko-agpsui2/po/
   developers/olv/openmoko-agpsui2/po/Makefile.in.in
   developers/olv/openmoko-agpsui2/po/POTFILES.in
   developers/olv/openmoko-agpsui2/src/
   developers/olv/openmoko-agpsui2/src/Makefile.am
   developers/olv/openmoko-agpsui2/src/agps.h
   developers/olv/openmoko-agpsui2/src/gllin.cpp
   developers/olv/openmoko-agpsui2/src/liblto.h
   developers/olv/openmoko-agpsui2/src/lto_download.cpp
   developers/olv/openmoko-agpsui2/src/lto_download.h
   developers/olv/openmoko-agpsui2/src/main.cpp
   developers/olv/openmoko-agpsui2/src/nmea.cpp
   developers/olv/openmoko-agpsui2/src/nmea.h
   developers/olv/openmoko-agpsui2/src/notebook.cpp
   developers/olv/openmoko-agpsui2/src/page_AZ.cpp
   developers/olv/openmoko-agpsui2/src/page_LTO.cpp
   developers/olv/openmoko-agpsui2/src/page_SS.cpp
   developers/olv/openmoko-agpsui2/src/page_add.cpp
   developers/olv/openmoko-agpsui2/src/page_log.cpp
   developers/olv/openmoko-agpsui2/src/page_main.cpp
   developers/olv/openmoko-agpsui2/src/page_map.cpp
   developers/olv/openmoko-agpsui2/src/page_speed.cpp
   developers/olv/openmoko-agpsui2/src/page_stats.cpp
   developers/olv/openmoko-agpsui2/src/page_stress.cpp
   developers/olv/openmoko-agpsui2/src/page_stress.h
   developers/olv/openmoko-agpsui2/src/pm_agps.cpp
   developers/olv/openmoko-agpsui2/src/pm_controls.cpp
   developers/olv/openmoko-agpsui2/src/sv_bar.h
Log:
Release openmoko-agpsui2 (with modifications) under GPLv2 or later.

The author is Ken Yale from Global Locate (now Broadcom).


Added: developers/olv/openmoko-agpsui2/AUTHORS
===================================================================
--- developers/olv/openmoko-agpsui2/AUTHORS	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/AUTHORS	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1 @@
+Ken Yale

Added: developers/olv/openmoko-agpsui2/COPYING
===================================================================
--- developers/olv/openmoko-agpsui2/COPYING	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/COPYING	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program 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; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: developers/olv/openmoko-agpsui2/ChangeLog
===================================================================

Added: developers/olv/openmoko-agpsui2/INSTALL
===================================================================
--- developers/olv/openmoko-agpsui2/INSTALL	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/INSTALL	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,234 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006 Free Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+

Added: developers/olv/openmoko-agpsui2/Makefile.am
===================================================================
--- developers/olv/openmoko-agpsui2/Makefile.am	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/Makefile.am	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,11 @@
+SUBDIRS = src data po
+
+# Extra clean files so that maintainer-clean removes *everything*
+MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub \
+                       configure depcomp install-sh ltmain.sh     \
+                       Makefile.in missing config.h.in            \
+                       intltool-extract intltool-extract.in \
+                       intltool-merge intltool-merge.in \
+                       intltool-update intltool-update.in \
+                       mkinstalldirs
+

Added: developers/olv/openmoko-agpsui2/NEWS
===================================================================

Added: developers/olv/openmoko-agpsui2/README
===================================================================
--- developers/olv/openmoko-agpsui2/README	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/README	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,3 @@
+Testing Application for Hammerhead AGPS Chip.
+
+Modified for generic chips outputing NMEA code.

Added: developers/olv/openmoko-agpsui2/autogen.sh
===================================================================
--- developers/olv/openmoko-agpsui2/autogen.sh	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/autogen.sh	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,4 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+glib-gettextize --force --copy || exit 1
+./configure --enable-maintainer-mode "$@"


Property changes on: developers/olv/openmoko-agpsui2/autogen.sh
___________________________________________________________________
Name: svn:executable
   + 

Added: developers/olv/openmoko-agpsui2/configure.ac
===================================================================
--- developers/olv/openmoko-agpsui2/configure.ac	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/configure.ac	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,32 @@
+AC_PREREQ(2.53)
+AC_INIT(openmoko-agpsui2, 1.0.0, noone at broadcom)
+AM_INIT_AUTOMAKE()
+AC_CONFIG_SRCDIR(src/main.cpp)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_PROG_LIBTOOL
+
+dnl i18n support
+GETTEXT_PACKAGE=Agpsui
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package])
+AC_SUBST(GETTEXT_PACKAGE)
+ALL_LINGUAS=""
+AM_GLIB_GNU_GETTEXT
+
+# base deps
+PKG_CHECK_MODULES(OPENMOKO, gtk+-2.0 gthread-2.0)
+LIBS="$LIBS $GTK_LIBS $OPENMOKO_LIBS"
+CFLAGS="$CFLAGS $OPENMOKO_CFLAGS"
+
+# output stuff
+AC_OUTPUT([
+Makefile
+lto/Makefile
+src/Makefile
+po/Makefile.in
+data/Makefile
+])

Added: developers/olv/openmoko-agpsui2/data/Makefile.am
===================================================================
--- developers/olv/openmoko-agpsui2/data/Makefile.am	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/data/Makefile.am	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,17 @@
+#
+# misc. data files
+#
+# None yet
+# dist_pkgdata_DATA = 
+
+#
+# desktop integration: .desktop file
+#
+desktopdir = $(datadir)/applications
+dist_desktop_DATA = openmoko-agpsui2.desktop
+
+#
+# desktop integration: application icon
+#
+#appicondir = $(datadir)/pixmaps
+#dist_appicon_DATA = openmoko-calculator.png

Added: developers/olv/openmoko-agpsui2/data/openmoko-agpsui2.desktop
===================================================================
--- developers/olv/openmoko-agpsui2/data/openmoko-agpsui2.desktop	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/data/openmoko-agpsui2.desktop	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Name=AGPS UI
+Comment=AGPS UI
+Encoding=UTF-8
+Version=1.0
+Type=Application
+Exec=openmoko-agpsui2
+Icon=fixme
+Terminal=false
+SingleInstance=true
+StartupNotify=true

Added: developers/olv/openmoko-agpsui2/lto/.deps/http_error_codes.Po
===================================================================
--- developers/olv/openmoko-agpsui2/lto/.deps/http_error_codes.Po	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/.deps/http_error_codes.Po	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1 @@
+# dummy

Added: developers/olv/openmoko-agpsui2/lto/.deps/http_fetcher.Po
===================================================================
--- developers/olv/openmoko-agpsui2/lto/.deps/http_fetcher.Po	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/.deps/http_fetcher.Po	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1 @@
+# dummy

Added: developers/olv/openmoko-agpsui2/lto/.deps/lto_get.Po
===================================================================
--- developers/olv/openmoko-agpsui2/lto/.deps/lto_get.Po	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/.deps/lto_get.Po	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1 @@
+# dummy

Added: developers/olv/openmoko-agpsui2/lto/.deps/lto_util.Po
===================================================================
--- developers/olv/openmoko-agpsui2/lto/.deps/lto_util.Po	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/.deps/lto_util.Po	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1 @@
+# dummy

Added: developers/olv/openmoko-agpsui2/lto/Makefile.am
===================================================================
--- developers/olv/openmoko-agpsui2/lto/Makefile.am	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/Makefile.am	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,11 @@
+localedir = $(datadir)/locale
+
+AM_CPPFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" -DLOCALEDIR=\"$(localedir)\"
+AM_CFLAGS =  -Wall -std=c99 -pedantic -DVERSION=HTTP_VERSION
+
+bin_PROGRAMS = lto_get lto_util
+
+lto_get_SOURCES = lto_get.c http_fetcher.c http_error_codes.c
+
+lto_util_SOURCES = lto_util.c
+

Added: developers/olv/openmoko-agpsui2/lto/http_error_codes.c
===================================================================
--- developers/olv/openmoko-agpsui2/lto/http_error_codes.c	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/http_error_codes.c	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,39 @@
+/* http_error_codes.c - Error code declarations
+
+	HTTP Fetcher 
+ 	Copyright (C) 2001, 2003, 2004 Lyle Hanson (lhanson at users.sourceforge.net)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Library General Public
+	License as published by the Free Software Foundation; either
+	version 2 of the License, or (at your option) any later version.
+
+	This library 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
+	Library General Public License for more details.
+
+	See LICENSE file for details
+ */
+
+
+	/* Note that '%d' cannot be escaped at this time */
+const char *http_errlist[] =
+	{
+	"Success",										/* HF_SUCCESS		*/
+	"Internal Error. What the hell?!",				/* HF_METAERROR		*/
+	"Got NULL url",									/* HF_NULLURL		*/
+	"Timed out, no metadata for %d seconds",		/* HF_HEADTIMEOUT 	*/
+	"Timed out, no data for %d seconds",			/* HF_DATATIMEOUT	*/
+	"Couldn't find return code in HTTP response",	/* HF_FRETURNCODE	*/
+	"Couldn't convert return code in HTTP response",/* HF_CRETURNCODE	*/
+	"Request returned a status code of %d",			/* HF_STATUSCODE	*/
+	"Couldn't convert Content-Length to integer",	/* HF_CONTENTLEN	*/
+	"Network error (description unavailable)",		/* HF_HERROR		*/
+	"Status code of %d but no Location: field",		/* HF_CANTREDIRECT  */
+	"Followed the maximum number of redirects (%d)" /* HF_MAXREDIRECTS  */
+	};
+
+	/* Used to copy in messages from http_errlist[] and replace %d's with
+	 *	the value of errorInt.  Then we can pass the pointer to THIS */
+char convertedError[128];

Added: developers/olv/openmoko-agpsui2/lto/http_error_codes.h
===================================================================
--- developers/olv/openmoko-agpsui2/lto/http_error_codes.h	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/http_error_codes.h	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,42 @@
+/* http_error_codes.h - Error code definitions
+
+	HTTP Fetcher
+	Copyright (C) 2001, 2003, 2004 Lyle Hanson (lhanson at users.sourceforge.net)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Library General Public
+	License as published by the Free Software Foundation; either
+	version 2 of the License, or (at your option) any later version.
+
+	This library 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
+	Library General Public License for more details.
+
+	See LICENSE file for details
+
+ */
+
+#ifndef HTTP_ERROR_CODES_H
+#define HTTP_ERROR_CODES_H
+
+/* Error sources */
+#define FETCHER_ERROR	0
+#define ERRNO			1
+#define H_ERRNO			2
+
+/* HTTP Fetcher error codes */
+#define HF_SUCCESS		0
+#define HF_METAERROR	1
+#define HF_NULLURL		2
+#define HF_HEADTIMEOUT	3
+#define HF_DATATIMEOUT	4
+#define HF_FRETURNCODE	5
+#define HF_CRETURNCODE	6
+#define HF_STATUSCODE	7
+#define HF_CONTENTLEN	8
+#define HF_HERROR		9
+#define HF_CANTREDIRECT 10
+#define HF_MAXREDIRECTS 11
+
+#endif

Added: developers/olv/openmoko-agpsui2/lto/http_fetcher.c
===================================================================
--- developers/olv/openmoko-agpsui2/lto/http_fetcher.c	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/http_fetcher.c	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,823 @@
+/* http_fetcher.c - HTTP handling functions
+
+	HTTP Fetcher 
+	Copyright (C) 2001, 2003, 2004 Lyle Hanson (lhanson at users.sourceforge.net)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Library General Public
+	License as published by the Free Software Foundation; either
+	version 2 of the License, or (at your option) any later version.
+
+	This library 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
+	Library General Public License for more details.
+
+	See LICENSE file for details
+
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include "http_fetcher.h"
+
+extern void updateStatistics(int bytesRead, int contentLength);     // KEN
+
+/* Globals */
+int timeout = DEFAULT_READ_TIMEOUT;
+char *userAgent = NULL;
+char *referer = NULL;
+int hideUserAgent = 0;
+int hideReferer = 1;
+static int followRedirects = DEFAULT_REDIRECTS;	/* # of redirects to follow */
+extern const char *http_errlist[];	/* Array of HTTP Fetcher error messages */
+extern char convertedError[128];	/* Buffer to used when errors contain %d */
+static int errorSource = 0;
+static int http_errno = 0;
+static int errorInt = 0;			/* When the error message has a %d in it,
+									 *	this variable is inserted */
+
+
+	/* 
+	 * Actually downloads the page, registering a hit (donation)
+	 *	If the fileBuf passed in is NULL, the url is downloaded and then
+	 *	freed; otherwise the necessary space is allocated for fileBuf.
+	 *	Returns size of download on success, -1 on error is set, 
+	 */
+int http_fetch(const char *url_tmp, char **fileBuf)
+	{
+	fd_set rfds;
+	struct timeval tv;
+	char headerBuf[HEADER_BUF_SIZE];
+	char *tmp, *url, *pageBuf, *requestBuf = NULL, *host, *charIndex;
+	int sock, bytesRead = 0, contentLength = -1, bufsize = REQUEST_BUF_SIZE;
+	int i,
+		ret = -1,
+		tempSize,
+		selectRet,
+		found = 0,	/* For redirects */
+		redirectsFollowed = 0;
+
+
+	if(url_tmp == NULL)
+		{
+		errorSource = FETCHER_ERROR;
+		http_errno = HF_NULLURL;
+		return -1;
+		}
+
+	/* Copy the url passed in into a buffer we can work with, change, etc. */
+	url = malloc(strlen(url_tmp)+1);
+	if(url == NULL)
+		{
+		errorSource = ERRNO;
+		return -1;
+		}
+	strncpy(url, url_tmp, strlen(url_tmp) + 1);
+	
+	/* This loop allows us to follow redirects if need be.  An afterthought,
+	 * added to provide this basic functionality.  Will hopefully be designed
+	 * better in 2.x.x ;) */
+/*	while(!found &&
+		  (followRedirects < 0 || redirectsFollowed < followRedirects) )
+  */  do
+		{
+		/* Seek to the file path portion of the url */
+		charIndex = strstr(url, "://");
+		if(charIndex != NULL)
+			{
+			/* url contains a protocol field */
+			charIndex += strlen("://");
+			host = charIndex;
+			charIndex = strchr(charIndex, '/');
+			}
+		else
+			{
+			host = (char *)url;
+			charIndex = strchr(url, '/');
+			}
+
+		/* Compose a request string */
+		requestBuf = malloc(bufsize);
+		if(requestBuf == NULL)
+			{
+			free(url);
+			errorSource = ERRNO;
+			return -1;
+			}
+		requestBuf[0] = 0;
+
+		if(charIndex == NULL)
+			{
+			/* The url has no '/' in it, assume the user is making a root-level
+			 *	request */ 
+			tempSize = strlen("GET /") + strlen(HTTP_VERSION) + 2;
+			if(_checkBufSize(&requestBuf, &bufsize, tempSize) ||
+				snprintf(requestBuf, bufsize, "GET / %s\r\n", HTTP_VERSION) < 0)
+				{
+				free(url);
+				free(requestBuf);
+				errorSource = ERRNO;
+				return -1;
+				}
+			}
+		else
+			{
+			tempSize = strlen("GET ") + strlen(charIndex) +
+  	          strlen(HTTP_VERSION) + 4;
+		 	/* + 4 is for ' ', '\r', '\n', and NULL */
+                                    
+			if(_checkBufSize(&requestBuf, &bufsize, tempSize) ||
+					snprintf(requestBuf, bufsize, "GET %s %s\r\n",
+					charIndex, HTTP_VERSION) < 0)
+				{
+				free(url);
+				free(requestBuf);
+				errorSource = ERRNO;
+				return -1;
+				}
+			}
+
+		/* Null out the end of the hostname if need be */
+		if(charIndex != NULL)
+			*charIndex = 0;
+
+		/* Use Host: even though 1.0 doesn't specify it.  Some servers
+		 *	won't play nice if we don't send Host, and it shouldn't
+		 *	hurt anything */
+		ret = bufsize - strlen(requestBuf); /* Space left in buffer */
+		tempSize = (int)strlen("Host: ") + (int)strlen(host) + 3;
+        /* +3 for "\r\n\0" */
+		if(_checkBufSize(&requestBuf, &bufsize, tempSize + 128))
+			{
+			free(url);
+			free(requestBuf);
+			errorSource = ERRNO;
+			return -1;
+			}
+		strcat(requestBuf, "Host: ");
+		strcat(requestBuf, host);
+		strcat(requestBuf, "\r\n");
+
+		if(!hideReferer && referer != NULL)	/* NO default referer */
+			{
+			tempSize = (int)strlen("Referer: ") + (int)strlen(referer) + 3;
+   	        /* + 3 is for '\r', '\n', and NULL */
+			if(_checkBufSize(&requestBuf, &bufsize, tempSize))
+				{
+				free(url);
+				free(requestBuf);
+				errorSource = ERRNO;
+				return -1;
+				}
+			strcat(requestBuf, "Referer: ");
+			strcat(requestBuf, referer);
+			strcat(requestBuf, "\r\n");
+			}
+
+		if(!hideUserAgent && userAgent == NULL)
+			{
+			tempSize = (int)strlen("User-Agent: ") +
+				(int)strlen(DEFAULT_USER_AGENT) + (int)strlen(VERSION) + 4;
+   	        /* + 4 is for '\', '\r', '\n', and NULL */
+			if(_checkBufSize(&requestBuf, &bufsize, tempSize))
+				{
+				free(url);
+				free(requestBuf);
+				errorSource = ERRNO;
+				return -1;
+				}
+			strcat(requestBuf, "User-Agent: ");
+			strcat(requestBuf, DEFAULT_USER_AGENT);
+			strcat(requestBuf, "/");
+			strcat(requestBuf, VERSION);
+			strcat(requestBuf, "\r\n");
+			}
+		else if(!hideUserAgent)
+			{
+			tempSize = (int)strlen("User-Agent: ") + (int)strlen(userAgent) + 3;
+   	        /* + 3 is for '\r', '\n', and NULL */
+			if(_checkBufSize(&requestBuf, &bufsize, tempSize))
+				{
+				free(url);
+				free(requestBuf);
+				errorSource = ERRNO;
+				return -1;
+				}
+			strcat(requestBuf, "User-Agent: ");
+			strcat(requestBuf, userAgent);
+			strcat(requestBuf, "\r\n");
+			}
+
+		tempSize = (int)strlen("Connection: Close\r\n\r\n");
+		if(_checkBufSize(&requestBuf, &bufsize, tempSize))
+			{
+			free(url);
+			free(requestBuf);
+			errorSource = ERRNO;
+			return -1;
+			}
+		strcat(requestBuf, "Connection: Close\r\n\r\n");
+
+		/* Now free any excess memory allocated to the buffer */
+		tmp = realloc(requestBuf, strlen(requestBuf) + 1);
+		if(tmp == NULL)
+			{
+			free(url);
+			free(requestBuf);
+			errorSource = ERRNO;
+			return -1;
+			}
+		requestBuf = tmp;
+
+		sock = makeSocket(host);		/* errorSource set within makeSocket */
+		if(sock == -1) { free(url); free(requestBuf); return -1;}
+
+		free(url);
+        url = NULL;
+
+		if(write(sock, requestBuf, strlen(requestBuf)) == -1)
+			{
+			close(sock);
+			free(requestBuf);
+			errorSource = ERRNO;
+			return -1;
+			}
+
+		free(requestBuf);
+        requestBuf = NULL;
+
+		/* Grab enough of the response to get the metadata */
+		ret = _http_read_header(sock, headerBuf);	/* errorSource set within */
+		if(ret < 0) { close(sock); return -1; }
+
+		/* Get the return code */
+		charIndex = strstr(headerBuf, "HTTP/");
+		if(charIndex == NULL)
+			{
+			close(sock);
+			errorSource = FETCHER_ERROR;
+			http_errno = HF_FRETURNCODE;
+			return -1;
+			}
+		while(*charIndex != ' ')
+			charIndex++;
+		charIndex++;
+
+		ret = sscanf(charIndex, "%d", &i);
+		if(ret != 1)
+			{
+			close(sock);
+			errorSource = FETCHER_ERROR;
+			http_errno = HF_CRETURNCODE;
+			return -1;
+			}
+		if(i<200 || i>307)
+			{
+			close(sock);
+			errorInt = i;	/* Status code, to be inserted in error string */
+			errorSource = FETCHER_ERROR;
+			http_errno = HF_STATUSCODE;
+			return -1;
+			}
+
+		/* If a redirect, repeat operation until final URL is found or we
+		 *  redirect followRedirects times.  Note the case sensitive "Location",
+		 *  should probably be made more robust in the future (without relying
+		 *  on the non-standard strcasecmp()).
+		 * This bit mostly by Dean Wilder, tweaked by me */
+		if(i >= 300)
+			{
+		    redirectsFollowed++;
+
+			/* Pick up redirect URL, allocate new url, and repeat process */
+			charIndex = strstr(headerBuf, "Location:");
+			if(!charIndex)
+				{
+				close(sock);
+				errorInt = i; /* Status code, to be inserted in error string */
+				errorSource = FETCHER_ERROR;
+				http_errno = HF_CANTREDIRECT;
+				return -1;
+				}
+			charIndex += strlen("Location:");
+            /* Skip any whitespace... */
+            while(*charIndex != '\0' && isspace(*charIndex))
+                charIndex++;
+            if(*charIndex == '\0')
+                {
+				close(sock);
+				errorInt = i; /* Status code, to be inserted in error string */
+				errorSource = FETCHER_ERROR;
+				http_errno = HF_CANTREDIRECT;
+				return -1;
+                }
+
+			i = strcspn(charIndex, " \r\n");
+			if(i > 0)
+				{
+				url = (char *)malloc(i + 1);
+				strncpy(url, charIndex, i);
+				url[i] = '\0';
+				}
+			else
+                /* Found 'Location:' but contains no URL!  We'll handle it as
+                 * 'found', hopefully the resulting document will give the user
+                 * a hint as to what happened. */
+                found = 1;
+            }
+		else
+			found = 1;
+	    } while(!found &&
+                (followRedirects < 0 || redirectsFollowed <= followRedirects) );
+
+    if(url) /* Redirection code may malloc this, then exceed followRedirects */
+        {
+        free(url);
+        url = NULL;
+        }
+    
+    if(redirectsFollowed >= followRedirects && !found)
+        {
+        close(sock);
+    	errorInt = followRedirects; /* To be inserted in error string */
+    	errorSource = FETCHER_ERROR;
+    	http_errno = HF_MAXREDIRECTS;
+	    return -1;
+        }
+	
+	/*
+	 * Parse out about how big the data segment is.
+	 *	Note that under current HTTP standards (1.1 and prior), the
+	 *	Content-Length field is not guaranteed to be accurate or even present. 
+	 *	I just use it here so I can allocate a ballpark amount of memory.
+	 *
+	 * Note that some servers use different capitalization
+	 */
+	charIndex = strstr(headerBuf, "Content-Length:");
+	if(charIndex == NULL)
+		charIndex = strstr(headerBuf, "Content-length:");
+
+	if(charIndex != NULL)
+		{
+		ret = sscanf(charIndex + strlen("content-length: "), "%d",
+			&contentLength);
+		if(ret < 1)
+			{
+			close(sock);
+			errorSource = FETCHER_ERROR;
+			http_errno = HF_CONTENTLEN;
+			return -1;
+			}
+		}
+	
+	/* Allocate enough memory to hold the page */
+	if(contentLength == -1)
+		contentLength = DEFAULT_PAGE_BUF_SIZE;
+
+	pageBuf = (char *)malloc(contentLength);
+	if(pageBuf == NULL)
+		{
+		close(sock);
+		errorSource = ERRNO;
+		return -1;
+		}
+
+    updateStatistics(bytesRead, contentLength);     // KEN
+
+	/* Begin reading the body of the file */
+	while(ret > 0)
+		{
+		FD_ZERO(&rfds);
+		FD_SET(sock, &rfds);
+		tv.tv_sec = timeout; 
+		tv.tv_usec = 0;
+
+		if(timeout >= 0)
+			selectRet = select(sock+1, &rfds, NULL, NULL, &tv);
+		else		/* No timeout, can block indefinately */
+			selectRet = select(sock+1, &rfds, NULL, NULL, NULL);
+
+		if(selectRet == 0)
+			{
+			errorSource = FETCHER_ERROR;
+			http_errno = HF_DATATIMEOUT;
+			errorInt = timeout;
+			close(sock);
+			free(pageBuf);
+			return -1;
+			}
+		else if(selectRet == -1)
+			{
+			close(sock);
+			free(pageBuf);
+			errorSource = ERRNO;
+			return -1;
+			}
+
+		ret = read(sock, pageBuf + bytesRead, contentLength);
+		if(ret == -1)
+			{
+			close(sock);
+			free(pageBuf);
+			errorSource = ERRNO;
+			return -1;
+			}
+
+		bytesRead += ret;
+
+                updateStatistics(bytesRead, contentLength);     // KEN
+
+		if(ret > 0)
+			{
+			/* To be tolerant of inaccurate Content-Length fields, we'll
+			 *	allocate another read-sized chunk to make sure we have
+			 *	enough room.
+			 */
+			tmp = (char *)realloc(pageBuf, bytesRead + contentLength);
+			if(tmp == NULL)
+				{
+				close(sock);
+				free(pageBuf);
+				errorSource = ERRNO;
+				return -1;
+				}
+            pageBuf = tmp;
+			}
+		}
+	
+	/*
+	 * The download buffer is too large.  Trim off the safety padding.
+     * Note that we add one NULL byte to the end of the data, as it may not
+     *  already be NULL terminated and we can't be sure what type of data it
+     *  is or what the caller will do with it.
+	 */
+	tmp = (char *)realloc(pageBuf, bytesRead + 1);
+		/* tmp shouldn't be null, since we're _shrinking_ the buffer,
+		 *	and if it DID fail, we could go on with the too-large buffer,
+		 *	but something would DEFINATELY be wrong, so we'll just give
+		 *	an error message */
+	if(tmp == NULL)
+		{
+		close(sock);
+		free(pageBuf);
+		errorSource = ERRNO;
+		return -1;
+		}
+    pageBuf = tmp;
+    pageBuf[bytesRead] = '\0';  /* NULL terminate the data */
+
+	if(fileBuf == NULL)	/* They just wanted us to "hit" the url */
+		free(pageBuf);
+	else
+		*fileBuf = pageBuf;
+
+	close(sock);
+	return bytesRead;
+	}
+
+
+
+	/*
+	 * Changes the User Agent.  Returns 0 on success, -1 on error. 
+	 */
+int http_setUserAgent(const char *newAgent)
+	{
+	static int freeOldAgent = 0; /* Indicates previous malloc's */
+	char *tmp;
+
+	if(newAgent == NULL)
+		{
+		if(freeOldAgent) free(userAgent);
+		userAgent = NULL;
+		hideUserAgent = 1;
+		}
+	else
+		{
+		tmp = (char *)malloc(strlen(newAgent));
+		if(tmp == NULL) { errorSource = ERRNO; return -1; }
+		if(freeOldAgent) free(userAgent);
+		userAgent = tmp;
+		strcpy(userAgent, newAgent);
+		freeOldAgent = 1;
+		hideUserAgent = 0;
+		}
+
+	return 0;
+	}
+
+
+
+	/*
+	 * Changes the Referer.  Returns 0 on success, -1 on error
+	 */
+int http_setReferer(const char *newReferer)
+	{
+	static int freeOldReferer = 0; /* Indicated previous malloc's */
+	char *tmp;
+
+	if(newReferer == NULL)
+		{
+		if(freeOldReferer) free(referer);
+		referer = NULL;
+		hideReferer = 1;
+		}
+	else
+		{
+		tmp = (char *)malloc(strlen(newReferer));
+		if(tmp == NULL) { errorSource = ERRNO; return -1; }
+		if(freeOldReferer) free(referer);
+		referer = tmp;
+		strcpy(referer, newReferer);
+		freeOldReferer = 1;
+		hideReferer = 0;
+		}
+	
+	return 0;
+	}
+
+
+
+	/*
+	 * Changes the amount of time that HTTP Fetcher will wait for data
+	 *	before timing out on reads
+	 */
+void http_setTimeout(int seconds) { timeout = seconds; }
+
+
+
+	/*
+	 * Changes the number of HTTP redirects HTTP Fetcher will automatically
+	 *	follow.  If a request returns a status code of 3XX and contains
+	 *	a "Location:" field, the library will transparently follow up to
+	 *	the specified number of redirects.  With this implementation
+	 *	(which is just a stopgap, really) the caller won't be aware of any
+	 *	redirection and will assume the returned document came from the original
+	 *	URL.
+	 * To disable redirects, pass a 0.  To follow unlimited redirects (probably
+	 *  unwise), pass a negative value.  The default is to follow 3 redirects.
+	 */
+void http_setRedirects(int redirects) { followRedirects = redirects; }
+
+
+
+	/*
+	 * Puts the filename portion of the url into 'filename'.
+	 * Returns:
+	 *	0 on success
+	 *	1 when url contains no end filename (i.e., 'www.foo.com/'),
+	 *		and **filename should not be assumed to be valid
+	 *	-1 on error
+	 */
+int http_parseFilename(const char *url, char **filename)
+	{
+	char *ptr;
+
+	if(url == NULL)
+		{
+		errorSource = FETCHER_ERROR;
+		http_errno = HF_NULLURL;
+		return -1;
+		}
+
+	ptr = (char *)rindex(url, '/');
+	if(ptr == NULL)
+		/* Root level request, apparently */
+		return 1;
+
+	ptr++;
+	if(*ptr == '\0') return 1;
+
+	*filename = (char *)malloc(strlen(ptr));
+	if(*filename == NULL) { errorSource = ERRNO; return -1; }
+	strcpy(*filename, ptr);
+
+	return 0;
+	}
+
+	
+	
+	/* Depending on the source of error, calls either perror() or prints
+	 *	an HTTP Fetcher error message to stdout */
+void http_perror(const char *string)
+	{
+	if(errorSource == ERRNO)
+		perror(string);
+	else if(errorSource == H_ERRNO)
+		herror(string);
+	else if(errorSource == FETCHER_ERROR)
+		{
+		const char *stringIndex;                // KEN
+
+		if(strstr(http_errlist[http_errno], "%d") == NULL)
+			{
+			fputs(string, stderr);
+			fputs(": ", stderr);
+			fputs(http_errlist[http_errno], stderr);
+			fputs("\n", stderr);
+			}
+		else
+			{
+			/* The error string has a %d in it, we need to insert errorInt */
+			stringIndex = http_errlist[http_errno];
+			while(*stringIndex != '%')			/* Print up to the %d */
+				{
+				fputc(*stringIndex, stderr);
+				stringIndex++;
+				}
+			fprintf(stderr, "%d", errorInt);	/* Print the number */
+			stringIndex += 2;					/* Skip past the %d */
+			while(*stringIndex != 0)			/* Print up to the end NULL */
+				{
+				fputc(*stringIndex, stderr);
+				stringIndex++;
+				}
+			fputs("\n", stderr);
+			}
+		}
+	}
+
+
+
+	/* 
+	 * Returns a pointer to the current error description message. The
+	 *	message pointed to is only good until the next call to http_strerror(),
+	 *	so if you need to hold on to the message for a while you should make
+	 *	a copy of it
+	 */
+const char *http_strerror()
+	{
+	extern int errno;
+	
+	if(errorSource == ERRNO)
+		return strerror(errno);
+	else if(errorSource == H_ERRNO)
+#ifdef HAVE_HSTRERROR
+		return hstrerror(h_errno);
+#else
+		return http_errlist[HF_HERROR];
+#endif
+	else if(errorSource == FETCHER_ERROR)
+		{
+		if(strstr(http_errlist[http_errno], "%d") == NULL)
+			return http_errlist[http_errno];
+		else
+			{
+			/* The error string has a %d in it, we need to insert errorInt.
+			 *	convertedError[128] has been declared for that purpose */
+			const char* stringIndex;        // KEN
+            const char* originalError;      // KEN
+		
+			originalError = http_errlist[http_errno];
+			convertedError[0] = 0;		/* Start off with NULL */
+			stringIndex = strstr(originalError, "%d");
+			strncat(convertedError, originalError,		/* Copy up to %d */
+				abs(stringIndex - originalError));
+			sprintf(&convertedError[strlen(convertedError)],"%d",errorInt);
+			stringIndex += 2;		/* Skip past the %d */
+			strcat(convertedError, stringIndex);
+
+			return convertedError;
+			}
+		}
+		
+	return http_errlist[HF_METAERROR];	/* Should NEVER happen */
+	}
+
+	
+	/*
+	 * Reads the metadata of an HTTP response.
+	 * Perhaps a little inefficient, as it reads 1 byte at a time, but
+	 *	I don't think it's that much of a loss (most headers aren't HUGE).
+	 * Returns:
+	 *	# of bytes read on success, or
+	 *	-1 on error
+	 */
+int _http_read_header(int sock, char *headerPtr)
+	{
+	fd_set rfds;
+	struct timeval tv;
+	int bytesRead = 0, newlines = 0, ret, selectRet;
+
+	while(newlines != 2 && bytesRead != HEADER_BUF_SIZE)
+		{
+		FD_ZERO(&rfds);
+		FD_SET(sock, &rfds);
+		tv.tv_sec = timeout; 
+		tv.tv_usec = 0;
+
+		if(timeout >= 0)
+			selectRet = select(sock+1, &rfds, NULL, NULL, &tv);
+		else		/* No timeout, can block indefinately */
+			selectRet = select(sock+1, &rfds, NULL, NULL, NULL);
+		
+		if(selectRet == 0)
+			{
+			errorSource = FETCHER_ERROR;
+			http_errno = HF_HEADTIMEOUT;
+			errorInt = timeout;
+			return -1;
+			}
+		else if(selectRet == -1) { errorSource = ERRNO; return -1; }
+
+		ret = read(sock, headerPtr, 1);
+		if(ret == -1) { errorSource = ERRNO; return -1; }
+		bytesRead++;
+
+		if(*headerPtr == '\r')			/* Ignore CR */
+			{
+			/* Basically do nothing special, just don't set newlines
+			 *	to 0 */
+			headerPtr++;
+			continue;
+			}
+		else if(*headerPtr == '\n')		/* LF is the separator */
+			newlines++;
+		else
+			newlines = 0;
+
+		headerPtr++;
+		}
+
+	headerPtr -= 3;		/* Snip the trailing LF's */
+	*headerPtr = '\0';
+	return bytesRead;
+	}
+
+
+
+	/*
+	 * Opens a TCP socket and returns the descriptor
+	 * Returns:
+	 *	socket descriptor, or
+	 *	-1 on error
+	 */
+int makeSocket(const char *host)
+	{
+	int sock;										/* Socket descriptor */
+	struct sockaddr_in sa;							/* Socket address */
+	struct hostent *hp;								/* Host entity */
+	int ret;
+    int port;
+    char *p;
+	
+    /* Check for port number specified in URL */
+    p = strchr(host, ':');
+    if(p)
+        {
+        port = atoi(p + 1);
+        *p = '\0';
+        }
+    else
+        port = PORT_NUMBER;
+
+	hp = gethostbyname(host);
+	if(hp == NULL) { errorSource = H_ERRNO; return -1; }
+		
+	/* Copy host address from hostent to (server) socket address */
+	memcpy((char *)&sa.sin_addr, (char *)hp->h_addr, hp->h_length);
+	sa.sin_family = hp->h_addrtype;		/* Set service sin_family to PF_INET */
+	sa.sin_port = htons(port);      	/* Put portnum into sockaddr */
+
+	sock = socket(hp->h_addrtype, SOCK_STREAM, 0);
+	if(sock == -1) { errorSource = ERRNO; return -1; }
+
+	ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa));
+	if(ret == -1) { errorSource = ERRNO; return -1; }
+
+	return sock;
+	}
+
+
+
+	/*
+	 * Determines if the given NULL-terminated buffer is large enough to
+	 * 	concatenate the given number of characters.  If not, it attempts to
+	 * 	grow the buffer to fit.
+	 * Returns:
+	 *	0 on success, or
+	 *	-1 on error (original buffer is unchanged).
+	 */
+int _checkBufSize(char **buf, int *bufsize, int more)
+	{
+	char *tmp;
+	int roomLeft = *bufsize - (strlen(*buf) + 1);
+	if(roomLeft > more)
+		return 0;
+	tmp = realloc(*buf, *bufsize + more + 1);
+	if(tmp == NULL)
+		return -1;
+	*buf = tmp;
+	*bufsize += more + 1;
+	return 0;
+	}

Added: developers/olv/openmoko-agpsui2/lto/http_fetcher.h
===================================================================
--- developers/olv/openmoko-agpsui2/lto/http_fetcher.h	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/http_fetcher.h	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,159 @@
+/* http_fetcher.h - HTTP handling functions
+
+	HTTP Fetcher
+	Copyright (C) 2001, 2003, 2004 Lyle Hanson (lhanson at users.sourceforge.net)
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Library General Public
+	License as published by the Free Software Foundation; either
+	version 2 of the License, or (at your option) any later version.
+
+	This library 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
+	Library General Public License for more details.
+
+	See LICENSE file for details
+									
+ */
+
+#ifndef HTTP_FETCHER_H
+#define HTTP_FETCHER_H
+
+#include "http_error_codes.h"
+
+#define PORT_NUMBER 			80
+#define HTTP_VERSION 			"HTTP/1.0"
+#define DEFAULT_USER_AGENT		"HTTP Fetcher"
+#define DEFAULT_READ_TIMEOUT	30		/* Seconds to wait before giving up
+										 *	when no data is arriving */
+	 
+#define REQUEST_BUF_SIZE 		1024
+#define HEADER_BUF_SIZE 		1024
+#define DEFAULT_PAGE_BUF_SIZE 	1024 * 200	/* 200K should hold most things */
+#define DEFAULT_REDIRECTS       3       /* Number of HTTP redirects to follow */
+
+
+
+/******************************************************************************/
+/**************** Function declarations and descriptions **********************/
+/******************************************************************************/
+
+/* 
+ * [!!! NOTE !!!]  All HTTP Fetcher functions return -1 on error.  You can
+ *	then either call http_perror to print the error message or call
+ *	http_strerror to get a pointer to it
+ */
+
+
+	/*
+	 * Download the page, registering a hit. If you pass it a NULL for fileBuf,
+	 *	'url' will be requested but will not remain in memory (useful for
+	 *	simply registering a hit).  Otherwise necessary space will be allocated
+	 *	and will be pointed to by fileBuf.  Note that a NULL byte is added to
+     *  the data, so the actual buffer will be the file size + 1.
+	 * Returns:
+	 *	# of bytes downloaded, or
+	 *	-1 on error
+	 */
+int http_fetch(const char *url, char **fileBuf);
+
+	/*
+	 * Changes the User Agent (shown to the web server with each request)
+	 *	Send it NULL to avoid telling the server a User Agent
+	 *	By default, the User Agent is sent (The default one unless changed)
+	 * Returns:
+	 *	0 on success, or
+	 *	-1 on error (previous value for agent remains unchanged)
+	 */
+int http_setUserAgent(const char *newAgent);
+
+	/*
+	 * Changes the Referer (shown to the web server with each request)
+	 *	Send it NULL to avoid thelling the server a Referer
+	 *	By default, no Referer is sent
+	 * Returns:
+	 *	0 on success, or
+	 *	-1 on error
+	 */
+int http_setReferer(const char *newReferer);
+
+	/*
+	 * Changes the maximum amount of time that HTTP Fetcher will wait on
+	 *	data.  If this many seconds elapses without more data from the
+	 *	server, http_fetch will return with an error.
+	 * If you pass a value less than 0, reads will not time out, potentially
+	 *	waiting forever (or until data shows up, whichever comes first)
+	 */
+void http_setTimeout(int seconds);
+
+	/*
+	 * Changes the number of HTTP redirects HTTP Fetcher will automatically
+	 *	follow.  If a request returns a status code of 3XX and contains
+	 *	a "Location:" field, the library will transparently follow up to
+	 *	the specified number of redirects.  With this implementation
+	 *	(which is just a stopgap, really) the caller won't be aware of any
+	 *	redirection and will assume the returned document came from the original
+	 *	URL.
+	 * To disable redirects, pass a 0.  To follow unlimited redirects (probably
+	 *  unwise), pass a negative value.  The default is to follow 3 redirects.
+	 */
+void http_setRedirects(int redirects);
+
+	/*
+	 * Takes a url and puts the filename portion of it into 'filename'.
+	 * Returns:
+	 *	0 on success, or
+	 *	1 when url contains no end filename (i.e., "www.foo.com/")
+	 *		and **filename should not be assumed to point to anything), or
+	 *	-1 on error
+	 */
+int http_parseFilename(const char *url, char **filename);
+
+	/*
+	 * Works like perror.  If an HTTP Fetcher function ever returns an
+	 *	error (-1), this will print a descriptive message to standard output
+	 */
+void http_perror(const char *string);
+
+	/*
+	 * Returns a pointer to the current error description message.  The
+	 *	message pointed to is only good until the next call to http_strerror(),
+	 *	so if you need to hold on to the message for a while you should make
+	 *	a copy of it.
+	 */
+const char *http_strerror();
+
+
+
+/******************************************************************************/
+/**** The following functions are used INTERNALLY by http_fetcher *************/
+/******************************************************************************/
+
+	/*
+	 * Reads the metadata of an HTTP response.  On success returns the number
+	 * Returns:
+	 *	# of bytes read on success, or
+	 *	-1 on error
+	 */
+int _http_read_header(int sock, char *headerPtr);
+
+	/*
+	 * Opens a TCP socket and returns the descriptor
+	 * Returns:
+	 *	socket descriptor, or
+	 *	-1 on error
+	 */
+int makeSocket(const char *host);
+
+	/*
+	 * Determines if the given NULL-terminated buffer is large enough to
+	 *	concatenate the given number of characters.  If not, it attempts to
+	 *	grow the buffer to fit.
+	 * Returns:
+	 *	0 on success, or
+	 *	-1 on error (original buffer is unchanged).
+	 */
+int _checkBufSize(char **buf, int *bufsize, int more);
+
+#endif

Added: developers/olv/openmoko-agpsui2/lto/lto_get.c
===================================================================
--- developers/olv/openmoko-agpsui2/lto/lto_get.c	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/lto_get.c	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,281 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <memory.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "http_fetcher.h"
+
+const char* argv0 = "<unknown>";
+const char* file  = 0;
+const char* url   = 0;
+int fd    = -1;
+int debug =  0;
+int sim   =  0;
+
+void updateStatistics(int bytesRead, int contentLength);
+void lto_progress();
+int sim_fetch(const char* url, char** fileBuf);
+
+// const char* default_url  = "http://gllto.glpals.com/7day/v2/latest/lto2.dat";
+const char* default_url  = "http://66.35.236.20/7day/v2/latest/lto2.dat";
+const char* default_file = "./lto2.dat";
+
+//-----------------------------------------------------------------------------
+//
+//      lto_get()
+//
+//  USAGE:
+//      lto_get -default [+DEBUG]
+//      lto_get <url> <file> [+DEBUG]
+//
+//  DESCRPIPTION:
+//      copy file from <url> to <file>
+//      Report to stdout:
+//          <done>=N        When done.  N is the file size in bytes.
+//                          Exit 0.
+//
+//          <percent>=0..100
+//                          During the download itself.
+//
+//          <progress>=A..Z,a..z
+//                          During the download itself.
+//
+//          <err>="...."    Upon error.
+//                          Exit 1.
+//
+//-----------------------------------------------------------------------------
+
+int
+main(int argc, char** argv)
+{
+    int i = 0;
+
+    argv0 = argv[i];
+
+    for (++i; i < argc; ++i)
+    {
+        const char* a = argv[i];
+
+        if (!strcmp(a, "-help"))
+        {
+            printf( "<help>=\"\n"
+                    "lto_get version 0.04 %s\n"
+                    "lto_get <url> <file> [opts]\n"
+                    "lto_get -default [opts]\n"
+                    "   defaults are: url  %s\n"
+                    "                 file %s\n"
+                    "Options:\n"
+                    "    +DEBUG       enable more output\n"
+                    "    +SIM         simulate download and file creation\n"
+                    "\n",
+                            __DATE__,
+                            default_url, default_file);
+            return 1;
+        }
+
+        if (!strcmp(a, "-default"))
+        {
+            url  = default_url;
+            file = default_file;
+            continue;
+        }
+
+        if (!strcmp(a,"+DEBUG"))
+        {
+            debug = 1;
+            continue;
+        }
+
+        if (!strcmp(a,"+SIM"))
+        {
+            sim = 1;
+            continue;
+        }
+
+        if (!url)
+        {
+            url = a;
+            continue;
+        }
+        if (!file)
+        {
+            file = a;
+            continue;
+        }
+    }
+
+    if (debug)
+    {
+        printf("<debug>=\"url  %s\"\n", (url)  ? url  : "<null>" );
+        printf("<debug>=\"file %s\"\n", (file) ? file : "<null>" );
+    }
+
+    if (!url || !file)
+    {
+        printf("<err>=\"%s missing parameters\"\n", argv0);
+        return 1;
+    }
+
+    lto_progress();
+
+    fd = open(file, O_WRONLY | O_CREAT,
+                        S_IRUSR | S_IWUSR |
+                        S_IRGRP | S_IWGRP |
+                        S_IROTH | S_IWOTH   );
+    if (fd < 0)
+    {
+        printf("<err>=\"%s: open(%s) error %d %s\"\n", argv0, file,
+                                        errno, strerror(errno));
+        return 2;
+    }
+
+    lto_progress();
+
+    http_setTimeout(10);                // 10 seconds between packets max.
+{
+    char* fileBuf;
+    int   write_size = 0;
+    int   http_size;
+
+    if (sim)
+    {
+        http_size = sim_fetch(url, &fileBuf);
+    }
+    else
+    {
+        http_size = http_fetch(url, &fileBuf);
+    }
+
+    if (http_size <= 0)
+    {
+        printf("<err>=\"%s: http get(%s) error %s\"\n", argv0, url,
+                                        http_strerror());
+        close(fd);
+        return 2;
+    }
+    lto_progress();
+
+    write_size = write(fd, fileBuf, http_size);
+    lto_progress();
+    close(fd);
+    lto_progress();
+    if (write_size != http_size)
+    {
+        printf("<err>=\"%s: write(%s,%d) error %d %s\"\n",
+                                        argv0, file, http_size,
+                                        errno, strerror(errno));
+        return 2;
+    }
+    printf("<done>=%d\n", write_size);
+
+    return 0;
+}
+}
+
+//-----------------------------------------------------------------------------
+//
+//            updateStatistics()
+//
+//  DESCRPIPTION:
+//      Report data transfer percentage if we've made more than 1.9%
+//      progress.
+//
+//      Maintain the download statistics in terms of percent*10
+//
+//-----------------------------------------------------------------------------
+
+void
+updateStatistics(int bytesRead, int contentLength)
+{
+    static int last_percent_10 = -100;
+    int percent_10 = ((bytesRead * 1000) + 5) / contentLength;
+
+    // if (debug)
+    // {
+    //     printf("<debug>=\"percent_10(%d/%d = %d\"\n",
+    //                     bytesRead, contentLength, percent_10);
+    // }
+
+    if (((percent_10 - last_percent_10) > 19) || debug)
+    {
+        last_percent_10 = percent_10;
+        printf("<percent>=%d\n", percent_10/10);
+        fflush(stdout);
+    }
+}
+
+//-----------------------------------------------------------------------------
+//
+//            lto_progress()
+//
+//  DESCRPIPTION:
+//      Report the progress "A" to "Z". then "a" to "z" (if needed)
+//
+//-----------------------------------------------------------------------------
+
+void
+lto_progress()
+{
+    static char progress = 'a';
+    if (debug)
+    {
+        printf("<progress>=%c\n", progress);
+        fflush(stdout);
+    }
+    if (++progress == ('Z' + 1))
+    {
+        progress = 'a';
+    }
+    else if (progress == ('z' + 1))
+    {
+        progress = 'A';
+    }
+}
+
+//-----------------------------------------------------------------------------
+//
+//            sim_fetch()
+//
+//  DESCRPIPTION:
+//      Simulate the downloading of the code by sleep and dummy data
+//
+//-----------------------------------------------------------------------------
+
+int
+sim_fetch(const char* url, char** fileBuf)
+{
+    const int fileSize = 10000;
+    const int nLoops   = 18;
+    const int loopSize = fileSize/nLoops;
+    int written = 0;
+    int loop;
+
+    char* data = (char*) malloc(fileSize);
+
+    if (debug)
+    {
+        printf("<debug>=\"simulating file size %d in %d loops\"\n",
+                    fileSize, nLoops);
+    }
+
+    for (loop = 0; loop <= nLoops; ++loop)
+    {
+        updateStatistics(written, fileSize);
+        sleep(1);
+        written += loopSize;
+        if (written > fileSize)
+        {
+            written = fileSize;
+            updateStatistics(written, fileSize);
+            break;
+        }
+    }
+
+    *fileBuf = data;
+    return fileSize;
+}

Added: developers/olv/openmoko-agpsui2/lto/lto_util.c
===================================================================
--- developers/olv/openmoko-agpsui2/lto/lto_util.c	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/lto/lto_util.c	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,209 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static int read_output(int fd);
+
+//-----------------------------------------------------------------------------
+//
+//      lto_util()
+//
+//  USAGE:
+//      lto_util
+//
+//  DESCRPIPTION:
+//      Test the lto_get program.
+//      Fork and exec lto_get() then
+//      track its progress and errors,
+//      then wait for it to exit.
+//
+//-----------------------------------------------------------------------------
+
+int
+main(int argc, char** argv)
+{
+    int fd[2];
+    int err = pipe(fd);
+    int pid = 0;
+
+    const char* lto_get = "./lto_get";
+    const char* url     = "http://gllto.glpals.com/7day/v2/latest/lto2.dat";
+    const char* file    = "./lto2.dat";
+    const char* debug   = "+DEBUG";
+
+    struct stat st;
+
+    //  Make sure that lto_get is an executable.
+ 
+    if (-1 == lstat(lto_get, &st))
+    {
+
+        printf("lto_util: lstat(%s) Error %d %s\n",
+                            lto_get, errno, strerror(errno));
+        return 1;
+    }
+
+    if (!(st.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)))
+    {
+        printf("lto_util: \"%s\" %x mode & %x execute = %x not executable\n",
+                    lto_get, st.st_mode,
+                    S_IXOTH | S_IXGRP | S_IXUSR,
+                    st.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR));
+        return 1;
+    }
+
+    if (err)
+    {
+        printf("pipe() err %d %s\n", errno, strerror(errno));
+        return 1;
+    }
+
+    pid = fork();
+    if (pid)            // we're the parent - wait for the child.
+    {
+        pid_t x;
+
+        close(fd[1]);       // close the write side
+
+        err = read_output(fd[0]);
+        x = waitpid(pid, 0, 0);
+        if (x != pid)
+        {
+            printf("%d = waitpid(%d) err %d %s\n",
+                    x, pid, errno, strerror(errno));
+        }
+    }
+    else
+    {
+        int fd1;
+        int fd2;
+        // we're the child - exec the program.
+
+        // close(0);        // close stdin
+        close(1);           // close stdout
+        close(fd[0]);       // close the write side
+
+        fd1 = dup(fd[1]);   // reopen stdout and stderr
+        if (fd1 != 1)
+        {
+            fprintf(stderr,"<err>=failed to reopen stdout %d %s\n",
+                        errno, strerror(errno));
+            return 3;
+        }
+
+        close(2);           // close stderr
+        fd2 = dup(fd[1]);   // to point to our pipe.
+        if (fd2 != 2)
+        {
+            printf("<err>=failed to reopen stderr %d %s\n",
+                        errno, strerror(errno));
+            return 3;
+        }
+
+        printf("<progress>=Z\n");       // indicate we're alive
+
+        err = execl(lto_get, lto_get, url, file, "+DEBUG", 0);
+        printf("<err>=\"execl(%s,%s,%s,%s) error %d %s\"\n",
+                    lto_get, url, file, debug,
+                    errno, strerror(errno));
+        return 3;
+    }
+}
+
+static int
+parse_output(const char* buf)
+{
+    // printf("parse_output(%s) %d\n", buf, strlen(buf));
+    if (!strncmp(buf, "<done>=", 7))
+    {
+        int n;
+
+        sscanf(buf + 7, "%d", &n);
+        printf("done - %d bytes\n", n);
+        return 0;
+    }
+
+    if (!strncmp(buf, "<percent>=", 10))
+    {
+        int n;
+
+        sscanf(buf + 10, "%d", &n);
+        printf("percent =  %d%%\n", n);
+        return -1;
+    }
+
+    if (!strncmp(buf, "<progress>=", 11))
+    {
+        char progress = buf[11];
+        printf("progress = '%c'\n", progress);
+        return -2;
+    }
+
+    if (!strncmp(buf, "<err>=", 6))
+    {
+        const char* err = buf + 6;
+        printf("error = %s\n", err);
+        return 1;
+    }
+
+    if (!strncmp(buf, "<debug>=", 8))
+    {
+        const char* dbg = buf + 8;
+        printf("debug = %s\n", dbg);
+        return -3;
+    }
+
+    printf("Unparsed output \"%s\"\n", buf);
+    return 2;
+}
+
+static int
+read_output(int fd)
+{
+    int offset = 0;
+    while (1)
+    {
+        char* p;
+        char* pNext;
+        char  buf[1024];
+        int n = read(fd, buf + offset, sizeof(buf) - offset);
+        int err;
+        if (n < 0)
+        {
+            printf("read(%d) error %d %s\n", n, errno, strerror(errno));
+            return 2;
+        }
+        else if (n > 0)
+        {
+            buf[n] = 0;
+            // printf("read(%d,%d,%s)\n", fd, n, buf);
+        }
+        buf[n] = 0;
+
+        for (p = buf; p < buf + n; p = pNext + 1)
+        {
+            pNext = strchr(p, '\n');
+            if (!pNext)
+            {
+                pNext = buf+n;
+                offset = pNext - p;
+                memcpy(buf, p, offset);
+                buf[offset] = 0;
+                // printf("Offset %d\n", offset);
+                break;
+            }
+            *pNext = 0;
+            err = parse_output(p);
+
+            if (err >= 0)
+            {
+                return err;
+            }
+        }
+    }
+}

Added: developers/olv/openmoko-agpsui2/po/Makefile.in.in
===================================================================
--- developers/olv/openmoko-agpsui2/po/Makefile.in.in	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/po/Makefile.in.in	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,271 @@
+# Makefile for program source directory in GNU NLS utilities package.
+# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper at gnu.ai.mit.edu>
+#
+# This file file be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+#
+# - Modified by Owen Taylor <otaylor at redhat.com> to use GETTEXT_PACKAGE
+#   instead of PACKAGE and to look for po2tbl in ./ not in intl/
+#
+# - Modified by jacob berkman <jacob at ximian.com> to install
+#   Makefile.in.in and po2tbl.sed.in for use with glib-gettextize
+
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+ at SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datarootdir = @datarootdir@
+datadir = @datadir@
+libdir = @libdir@
+localedir = $(libdir)/locale
+gnulocaledir = $(datadir)/locale
+gettextsrcdir = $(datadir)/glib-2.0/gettext/po
+subdir = po
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+MKINSTALLDIRS = $(top_srcdir)/@MKINSTALLDIRS@
+
+CC = @CC@
+GENCAT = @GENCAT@
+GMSGFMT = @GMSGFMT@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+XGETTEXT = @XGETTEXT@
+MSGMERGE = msgmerge
+
+DEFS = @DEFS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+
+INCLUDES = -I.. -I$(top_srcdir)/intl
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+SOURCES = 
+POFILES = @POFILES@
+GMOFILES = @GMOFILES@
+DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(GETTEXT_PACKAGE).pot \
+$(POFILES) $(GMOFILES) $(SOURCES)
+
+POTFILES = \
+
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+INSTOBJEXT = @INSTOBJEXT@
+
+.SUFFIXES:
+.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
+
+.c.o:
+	$(COMPILE) $<
+
+.po.pox:
+	$(MAKE) $(GETTEXT_PACKAGE).pot
+	$(MSGMERGE) $< $(srcdir)/$(GETTEXT_PACKAGE).pot -o $*.pox
+
+.po.mo:
+	$(MSGFMT) -o $@ $<
+
+.po.gmo:
+	file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \
+	  && rm -f $$file && $(GMSGFMT) $(MSGFMT_OPTS) -o $$file $<
+
+.po.cat:
+	sed -f ../intl/po2msg.sed < $< > $*.msg \
+	  && rm -f $@ && $(GENCAT) $@ $*.msg
+
+
+all: all- at USE_NLS@
+
+all-yes: $(CATALOGS)
+all-no:
+
+$(srcdir)/$(GETTEXT_PACKAGE).pot: $(POTFILES)
+	$(XGETTEXT) --default-domain=$(GETTEXT_PACKAGE) --directory=$(top_srcdir) \
+	  --add-comments --keyword=_ --keyword=N_ \
+          --flag=g_strdup_printf:1:c-format \
+          --flag=g_string_printf:2:c-format \
+          --flag=g_string_append_printf:2:c-format \
+          --flag=g_error_new:3:c-format \
+          --flag=g_set_error:4:c-format \
+          --flag=g_markup_printf_escaped:1:c-format \
+          --flag=g_log:3:c-format \
+          --flag=g_print:1:c-format \
+          --flag=g_printerr:1:c-format \
+          --flag=g_printf:1:c-format \
+          --flag=g_fprintf:2:c-format \
+          --flag=g_sprintf:2:c-format \
+          --flag=g_snprintf:3:c-format \
+          --flag=g_scanner_error:2:c-format \
+          --flag=g_scanner_warn:2:c-format \
+	  --files-from=$(srcdir)/POTFILES.in \
+	&& test ! -f $(GETTEXT_PACKAGE).po \
+	   || ( rm -f $(srcdir)/$(GETTEXT_PACKAGE).pot \
+		&& mv $(GETTEXT_PACKAGE).po $(srcdir)/$(GETTEXT_PACKAGE).pot )
+
+install: install-exec install-data
+install-exec:
+install-data: install-data- at USE_NLS@
+install-data-no: all
+install-data-yes: all
+	if test -r "$(MKINSTALLDIRS)"; then \
+	  $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \
+	else \
+	  $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \
+	fi
+	@catalogs='$(CATALOGS)'; \
+	for cat in $$catalogs; do \
+	  cat=`basename $$cat`; \
+	  case "$$cat" in \
+	    *.gmo) destdir=$(gnulocaledir);; \
+	    *)     destdir=$(localedir);; \
+	  esac; \
+	  lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+	  dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \
+	  if test -r "$(MKINSTALLDIRS)"; then \
+	    $(MKINSTALLDIRS) $$dir; \
+	  else \
+	    $(SHELL) $(top_srcdir)/mkinstalldirs $$dir; \
+	  fi; \
+	  if test -r $$cat; then \
+	    $(INSTALL_DATA) $$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
+	    echo "installing $$cat as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \
+	  else \
+	    $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
+	    echo "installing $(srcdir)/$$cat as" \
+		 "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \
+	  fi; \
+	  if test -r $$cat.m; then \
+	    $(INSTALL_DATA) $$cat.m $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
+	    echo "installing $$cat.m as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \
+	  else \
+	    if test -r $(srcdir)/$$cat.m ; then \
+	      $(INSTALL_DATA) $(srcdir)/$$cat.m \
+		$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
+	      echo "installing $(srcdir)/$$cat as" \
+		   "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \
+	    else \
+	      true; \
+	    fi; \
+	  fi; \
+	done
+	if test "$(PACKAGE)" = "glib"; then \
+	  if test -r "$(MKINSTALLDIRS)"; then \
+	    $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
+	  else \
+	    $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
+	  fi; \
+	  $(INSTALL_DATA) $(srcdir)/Makefile.in.in \
+			  $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
+	else \
+	  : ; \
+	fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+	catalogs='$(CATALOGS)'; \
+	for cat in $$catalogs; do \
+	  cat=`basename $$cat`; \
+	  lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+	  rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
+	  rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
+	  rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
+	  rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
+	done
+	if test "$(PACKAGE)" = "glib"; then \
+	  rm -f $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
+	fi
+
+check: all
+
+dvi info tags TAGS ID:
+
+mostlyclean:
+	rm -f core core.* *.pox $(GETTEXT_PACKAGE).po *.old.po cat-id-tbl.tmp
+	rm -fr *.o
+
+clean: mostlyclean
+
+distclean: clean
+	rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
+
+maintainer-clean: distclean
+	@echo "This command is intended for maintainers to use;"
+	@echo "it deletes files that may require special tools to rebuild."
+	rm -f $(GMOFILES)
+
+distdir = ../$(GETTEXT_PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: update-po $(DISTFILES)
+	dists="$(DISTFILES)"; \
+	for file in $$dists; do \
+	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+	    || cp -p $(srcdir)/$$file $(distdir); \
+	done
+
+update-po: Makefile
+	$(MAKE) $(GETTEXT_PACKAGE).pot
+	tmpdir=`pwd`; \
+	cd $(srcdir); \
+	catalogs='$(CATALOGS)'; \
+	for cat in $$catalogs; do \
+	  cat=`basename $$cat`; \
+	  lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+	  echo "$$lang:"; \
+	  if $(MSGMERGE) $$lang.po $(GETTEXT_PACKAGE).pot -o $$tmpdir/$$lang.new.po; then \
+	    if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
+	      rm -f $$tmpdir/$$lang.new.po; \
+            else \
+	      if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
+	        :; \
+	      else \
+	        echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
+	        rm -f $$tmpdir/$$lang.new.po; \
+	        exit 1; \
+	      fi; \
+	    fi; \
+	  else \
+	    echo "msgmerge for $$cat failed!"; \
+	    rm -f $$tmpdir/$$lang.new.po; \
+	  fi; \
+	done
+
+# POTFILES is created from POTFILES.in by stripping comments, empty lines
+# and Intltool tags (enclosed in square brackets), and appending a full
+# relative path to them
+POTFILES: POTFILES.in
+	( if test 'x$(srcdir)' != 'x.'; then \
+	    posrcprefix='$(top_srcdir)/'; \
+	  else \
+	    posrcprefix="../"; \
+	  fi; \
+	  rm -f $@-t $@ \
+	    && (sed -e '/^#/d' 						\
+		    -e "s/^\[.*\] +//" 					\
+		    -e '/^[ 	]*$$/d' 				\
+		    -e "s at .*@	$$posrcprefix& \\\\@" < $(srcdir)/$@.in	\
+		| sed -e '$$s/\\$$//') > $@-t \
+	    && chmod a-w $@-t \
+	    && mv $@-t $@ )
+
+Makefile: Makefile.in.in ../config.status POTFILES
+	cd .. \
+	  && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \
+	       $(SHELL) ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: developers/olv/openmoko-agpsui2/po/POTFILES.in
===================================================================

Added: developers/olv/openmoko-agpsui2/src/Makefile.am
===================================================================
--- developers/olv/openmoko-agpsui2/src/Makefile.am	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/Makefile.am	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,30 @@
+localedir = $(datadir)/locale
+
+AM_CPPFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" -DLOCALEDIR=\"$(localedir)\"
+AM_CFLAGS =  @OPENMOKO_CFLAGS@ -Wall
+AM_CXXFLAGS = @OPENMOKO_CFLAGS@ -Wall
+
+bin_PROGRAMS = openmoko-agpsui2
+
+openmoko_agpsui2_SOURCES = \
+  lto_download.cpp \
+  main.cpp \
+  notebook.cpp \
+  page_AZ.cpp \
+  page_main.cpp \
+  page_speed.cpp \
+  page_stats.cpp \
+  pm_agps.cpp \
+  gllin.cpp \
+  nmea.cpp \
+  page_add.cpp \
+  page_LTO.cpp \
+  page_map.cpp \
+  page_SS.cpp \
+  page_stress.cpp \
+  page_log.cpp \
+  pm_controls.cpp
+
+# :-(
+openmoko_agpsui2_LDADD = -L. -lrt
+  

Added: developers/olv/openmoko-agpsui2/src/agps.h
===================================================================
--- developers/olv/openmoko-agpsui2/src/agps.h	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/agps.h	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AGPS_H_
+#define AGPS_H_
+
+#ifndef AGPS_H_
+#include "agps.h"
+#endif 
+
+#ifndef NMEA_H_
+#include "nmea.h"
+#endif 
+
+#include <gtk/gtk.h>
+
+#if 1 
+#define DEBUG_LV1
+#endif
+
+#if 0 
+#define DEBUG_LV2
+#endif
+
+#if 0 
+#define DEBUG_LV3
+#endif
+
+#if 0 
+#define DEBUG_LV4
+#endif
+
+#if 0 
+#define DEBUG_LV5
+#endif
+
+#if 0 
+#define DEBUG_LV6
+#endif
+
+// void agps_start(GtkWidget* label);
+// void agps_stop(void); 
+
+#endif

Added: developers/olv/openmoko-agpsui2/src/gllin.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/gllin.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/gllin.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,577 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* $Id: gllin.c $
+ *
+ * Global Locate driver for FIC GTA01 (OpenMoko Neo1973).
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <termios.h>
+#include <time.h>
+#include <stdio.h>
+#include <wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX        1024
+#endif
+
+typedef struct glData
+{
+    int pid;
+    int fd;
+} glData;
+
+static glData GL_DATA =
+{
+     0,         // pid
+    -1          // fd
+};
+
+#define pipeName        "/dev/ttySAC1"
+
+extern const char* gllin_stop();
+static void gllin_poweron(int on);
+extern void gllin_arg_set(int arg_max, int* pArgc, const char** pp_argv);
+extern void trace_arg(int argc, char** argv);
+extern void pm_controls_active(bool active);
+extern void runtime_init();
+
+extern int debug_all;
+
+//------------------------------------------------------------------------------------
+//
+//              isRunning()
+//
+//------------------------------------------------------------------------------------
+
+static int isRunning()
+{
+    // printf("isRunning pid %d   fd %d\n", GL_DATA.pid, GL_DATA.fd);
+
+    // if (GL_DATA.pid && (-1 != GL_DATA.fd))
+    if ((-1 != GL_DATA.fd))
+    {
+        return 1;
+    }
+    return 0;
+}
+
+//------------------------------------------------------------------------------------
+//
+//              gllin_conf_read()
+//
+//------------------------------------------------------------------------------------
+
+#define MAX_ARGS        20
+extern int nmea_log;
+int daemonize;
+
+static void gllin_conf_read(char* path, int* pArgc, char** argv)
+{
+    static char buf[4000];
+
+    memset(buf, 0, sizeof(buf));
+
+    int    f = open("/etc/gllin/gllin.conf", O_RDONLY);
+    int    n = read(f, buf, sizeof(buf) - 1);
+    char*  p = buf;
+    char*  pEnd;
+    int    argc = 0;
+    int    argMax = 0;
+    int    dummy;
+    int    skip_next_arg = 0;
+    daemonize = 0;
+
+    buf[sizeof(buf)-1] = 0;
+    if (n > 0) n = strlen(buf);
+
+    if (argv)
+    {
+        argv[0] = 0;
+    }
+
+    if (pArgc)
+    {
+        argMax = *pArgc - 1;
+    }
+    else
+    {
+        pArgc = &dummy;
+    }
+    *pArgc = 0;
+
+    close(f);
+
+    if (n <= 0)
+    {
+        strcpy(path, "./gllin");
+        *pArgc = 0;
+#ifdef DEBUG_LV1			
+        printf("gllin conf[0] %s\n", path);
+#endif
+        printf("%s/%d path %s\n", __FILE__, __LINE__, path);
+        return;
+    }
+
+    //  Get the path.
+    {
+        char* s = path;
+        strncpy(s, p, PATH_MAX);
+        s[PATH_MAX-1] = 0;
+
+        while ((*s != ' ') && *s)
+        {
+            ++s;
+        }
+        if (*s == ' ')
+        {
+            *s = 0;
+            p += (s - path);
+        }
+    }
+
+    //  Split the config string into arguments.
+
+    if (argv) argv[argc++] = path;
+
+    for (pEnd = p + strlen(p); (argc < argMax) && (p < pEnd); ++p )
+    {
+        char* arg;
+        if (' ' == *p)
+        {
+            *p = 0;
+            continue;
+        }
+        if (!*p)
+        {
+            continue;
+        }
+
+        if (argv) argv[argc] = p;
+        do
+        {
+            ++p;
+        } while ((*p != ' ') && (*p != '\n') && (*p != '\r') && *p);
+        *p = 0;
+
+        ++argc;
+        arg = argv[argc-1];
+        if (!nmea_log)
+        {
+            if (skip_next_arg)
+            {
+                argv[--argc] = 0;
+                skip_next_arg = 0;
+            }
+            else if (strstr(arg, "log"))
+            {
+                argv[--argc] = 0;
+                skip_next_arg = 1;
+            }
+        }
+        if (!strcmp(arg, "+daemon"))
+        {
+            daemonize = 1;
+        }
+    }
+
+    if (argv)
+    {
+        argv[argc] = 0;
+    }
+    *pArgc     = argc;
+}
+
+//------------------------------------------------------------------------------------
+//
+//              gllin_detect()
+//
+//   1)  Does the /etc/gllin/gllin.conf file exist?
+//   2)  If so, parse the command line.  Does the executable exist?
+//   3)  If not, parse the default command line.  Does THAT executable exist?
+//
+//------------------------------------------------------------------------------------
+
+const char* gllin_detect(void)
+{
+    struct stat st;
+    char   path[PATH_MAX];
+
+    return NULL;
+
+    if (isRunning())
+    {
+        return 0;
+    }
+
+    mkfifo(pipeName, O_CREAT | O_EXCL);
+    chmod(pipeName, S_IRUSR | S_IWUSR |
+                    S_IRGRP | S_IWGRP |
+                    S_IROTH | S_IWOTH);
+
+    gllin_conf_read(path, 0, 0);
+ 
+    if (-1 == lstat(path, &st))
+    {
+        //int   err  = errno;                     /* UNUSED */
+        //char* sErr = strerror(errno);           /* UNUSED */
+
+        // printf("gllin: lstat(%s) Error %d %s\n", path, err, sErr);
+        return "executable not found";
+    }
+
+    if (st.st_mode & S_IXOTH)
+    {
+#ifdef DEBUG_LV1			
+        printf("gllin: gllin_detect OK %d\n",st.st_mode);
+#endif
+        return 0;
+    }
+
+#ifdef DEBUG_LV1			
+    printf("gllin: gllin_detect FAIL %d\n",st.st_mode);
+#endif
+    return "gllin not executable";
+}
+
+//------------------------------------------------------------------------------
+//
+//              gllin_fork()
+//
+//      Fork and exec the GLLIN.
+//
+//------------------------------------------------------------------------------
+
+static void
+gllin_fork()
+{
+    int    argc = MAX_ARGS;
+    char   path[PATH_MAX];
+    char*  argv[MAX_ARGS+1];
+    char** pargv = argv;
+    int rc = 0;
+
+    gllin_poweron(1);
+    return;
+
+    gllin_conf_read(path,     &argc, pargv);
+    gllin_arg_set  (MAX_ARGS, &argc, const_cast<const char**> (argv));
+    trace_arg(argc, argv);
+
+    pm_controls_active(false);          // Turn off the main controls
+    runtime_init();
+
+    GL_DATA.pid = fork();
+    if (!GL_DATA.pid)
+    {
+        close(GL_DATA.fd);
+        GL_DATA.fd = -1;
+        rc = execvp(path, argv);
+        exit(2);
+    }
+    if (daemonize)
+    {
+        int stat;
+        waitpid(GL_DATA.pid, &stat, 0);
+    }
+}
+
+//------------------------------------------------------------------------------
+//
+//              gllin_start()
+//
+//------------------------------------------------------------------------------
+
+#define DEFAULT_GLLIN_WD        "/tmp"
+
+int gllin_fd(void)
+{
+    return GL_DATA.fd;
+}
+
+static int gllin_uart_speed(void)
+{
+	int ret;
+	struct termios ti;
+
+	ret = tcgetattr(GL_DATA.fd, &ti);
+	if (ret<0)
+		return ret;
+
+	ret = cfsetispeed(&ti, B0);
+	if (ret < 0)
+		return ret;
+
+	ret = cfsetospeed(&ti, B9600);
+	if (ret < 0)
+		return ret;
+
+	ti.c_cflag &= ~CRTSCTS;
+	ti.c_lflag &= ~ICANON;
+	ti.c_lflag &= ~ECHO;
+
+	return tcsetattr(GL_DATA.fd, TCSANOW, &ti);
+}
+
+const char* gllin_start(void)
+{
+    int running = isRunning();
+    if (running)
+    {
+        return 0;
+    }
+
+    gllin_stop();
+
+    GL_DATA.fd = open(pipeName, O_RDWR);
+    if (gllin_uart_speed() < 0)
+	    return "Fail to set speed";
+
+#ifdef DEBUG_LV1			
+    printf("gllin_start open(%s) error %s\n",
+                                        pipeName, strerror(errno));
+#endif
+    if (-1 == GL_DATA.fd)
+    {
+        return "Can't open /tmp/nmeaNP";
+    }
+
+    const char* gllin_wd = getenv("GLLIN_WD");
+    if (!gllin_wd) gllin_wd = DEFAULT_GLLIN_WD;
+    if (chdir(gllin_wd))
+    {
+        return "Can't reach GLLIN_WD";
+    }
+
+    gllin_fork();
+
+    printf("gllin_start pid %d fd %d\n", GL_DATA.pid, GL_DATA.fd);
+
+    if (isRunning()) return 0;
+    return "Failed to start gllin";
+}
+
+//------------------------------------------------------------------------------
+//
+//              gllin_stop()
+//
+//------------------------------------------------------------------------------
+
+extern void page_main_stop(const char* msg);
+
+const char* gllin_stop(void)
+{
+    page_main_stop(0);
+    pm_controls_active(true);           // Turn ON the main controls
+    close(GL_DATA.fd);
+    GL_DATA.fd = -1;
+    gllin_poweron(0);
+    return 0;
+}
+
+//------------------------------------------------------------------------------
+//
+//              gta02
+//
+//------------------------------------------------------------------------------
+
+static ssize_t bwrite(int fd, const void *buf, size_t count, int delay)
+{
+	size_t i;
+
+	if (delay)
+	{
+		for (i = 0; i < count; i++)
+		{
+			if (write(fd, (unsigned char *) buf + i, 1) != 1)
+				return -1;
+			usleep(delay * 1000);
+		}
+	}
+	else
+		return write(fd, (unsigned char *) buf, count);
+
+	return i;
+}
+
+static void gllin_ubx(char cls, char id, const unsigned char *ubx, int size, int delay)
+{
+	unsigned char header[6], checksum[2];
+	int i;
+
+	if (!GL_DATA.fd)
+		return;
+
+	header[0] = 0xb5;
+	header[1] = 0x62;
+	header[2] = cls;
+	header[3] = id;
+	header[4] = size & 0xff;
+	header[5] = (size >> 8) & 0xff;
+
+	checksum[0] = checksum[1] = 0;
+	for (i = 2; i < 6; i++)
+	{
+		checksum[0] += header[i];
+		checksum[1] += checksum[0];
+	}
+
+	for (i = 0; i < size; i++)
+	{
+		checksum[0] += ubx[i];
+		checksum[1] += checksum[0];
+	}
+
+	if (bwrite(GL_DATA.fd, header, 6, delay) != 6)
+		goto fail;
+
+	if (size)
+	{
+		if (bwrite(GL_DATA.fd, (void *) ubx, size, delay) != size)
+			goto fail;
+	}
+
+	if (bwrite(GL_DATA.fd, checksum, 2, delay) != 2)
+		goto fail;
+
+	if (debug_all)
+	{
+		printf("ubx sent: ");
+		for (i = 0; i < 6; i++)
+			printf("%02x ", header[i]);
+		if (size)
+		{
+			for (i = 0; i < size; i++)
+				printf("%02x ", ubx[i]);
+		}
+
+		printf("%02x %02x\n", checksum[0], checksum[1]);
+	}
+
+	return;
+
+fail:
+	printf("ubx failed\n");
+}
+
+#if 0
+static void gllin_nmea(const char *nmea)
+{
+	char buf[1024];
+	const char *p = nmea;
+	int n, checksum = 0;
+
+	if (!GL_DATA.fd)
+		return;
+
+	while (*p)
+		checksum ^= *p++;
+
+	n = snprintf(buf, 256, "$%s*%02x\r\n", nmea, checksum);
+
+	if (bwrite(GL_DATA.fd, nmea, n, 0) != n)
+		printf("nmea failed\n");
+
+	printf("sent: %d: %s", n, buf);
+}
+
+static void gllin_poll_status(void)
+{
+	unsigned char buf[] = { 0x01, 0x03, 0x1 };
+
+	gllin_ubx(0x06, 0x01, buf, sizeof(buf), 4);
+}
+#endif
+
+static void gllin_poweron(int on)
+{
+	int fd;
+	char cmd;
+
+	fd = open("/sys/devices/platform/gta02-pm-gps.0/power_on", O_WRONLY);
+	if (!fd)
+		return;
+
+	cmd = (on) ? '1' : '0';
+
+	write(fd, &cmd, 1);
+
+	close(fd);
+
+	sleep(1);
+
+	/* initialize */
+	if (on)
+	{
+		//gllin_poll_status();
+		runtime_init();
+	}
+}
+
+void gllin_reset(char c)
+{
+	unsigned char ubx[4];
+	int bbr;
+
+	switch (c)
+	{
+	case 'c':
+		bbr = 0x7ff;
+		break;
+	case 'w':
+		bbr = 0x1;
+		break;
+	case 'h':
+		bbr = 0x0;
+		break;
+	}
+
+	ubx[0] = bbr & 0xff;
+	ubx[1] = (bbr >> 8) & 0xff;
+	ubx[2] = 0x8; /* stop GPS */
+	ubx[3] = 0x0;
+
+	gllin_ubx(0x06, 0x04, ubx, 4, 4);
+
+	sleep(2);
+
+	ubx[2] = 0x9; /* start GPS */
+	gllin_ubx(0x06, 0x04, ubx, 4, 4);
+
+	runtime_init();
+}

Added: developers/olv/openmoko-agpsui2/src/liblto.h
===================================================================
--- developers/olv/openmoko-agpsui2/src/liblto.h	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/liblto.h	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef LIB_LTO_H__
+#define LIB_LTO_H__                     // {
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+//      liblto.h
+//
+
+//-----------------------------------------------------------------------------------
+//
+//      Apply Aiding to the GLL
+//
+//-----------------------------------------------------------------------------------
+
+const char* ltoGetAiding(const char *lto_file_name);
+
+//-----------------------------------------------------------------------------------
+//
+//      Given an LTO file, check the expiration:
+//
+// Parameters:
+//      [input]  lto_file_name
+//      [output] *hours        Filled with a positive number if LTO is good.
+//                             Negative number if LTO is expired.
+//      [output] userMessage   Pointer to formatted string that is filled with
+//                             a description of LTO validity.
+//      [input]  buf_size      Size of the user message buffer.
+//
+// Returns:
+//      const char* errmsg:
+//              If 0, then there was no error.
+//              If non-zero, then the LTO is not valid or readable for
+//              the reason described in the string.
+//              For error return cases, the hours might be filled in
+//              with the hours since expiration or the hours until the
+//              LTO becomes valid.
+//
+//-----------------------------------------------------------------------------------
+
+const char* ltoGetExpiration(const char *lto_file_name,
+                             int*  hours,
+                             char* userMessage,
+                             unsigned long buf_size);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  // LIB_LTO_H__                     // }

Added: developers/olv/openmoko-agpsui2/src/lto_download.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/lto_download.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/lto_download.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,472 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "lto_download.h"
+#include "liblto.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <memory.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <gtk/gtk.h>
+
+//      See page_LTO.cpp for these:
+extern void lto_download_error(const char* msg);
+extern void lto_download_progress(char progress);
+extern void lto_download_percent(int n);
+extern void lto_download_done(void);
+
+static gint lto_cb_tag =  0;
+static int  lto_fd     = -1;
+static int  lto_pid    =  0;
+static bool lto_downloading_flag = false;
+
+static void lto_wait_for_stop(void);
+static void lto_fd_read(gpointer data, gint source, GdkInputCondition cond);
+static int  lto_read_output(void);
+static const char* ltoDownloadPidWait();
+static void lto_read_init();
+
+const char* cc_lto_get = "/home/root/gpsd/lto_get";
+// st char* cc_url     = "http://66.35.236.20"  "/7day/v2/latest/lto2.dat";
+const char* cc_url     = "http://gllto.glpals.com/7day/v2/latest/lto2.dat";
+const char* cc_file    = "/home/root/gpsd/lto2.dat";
+
+//-----------------------------------------------------------------------------------
+//
+//                      ltoRemove()
+//
+//-----------------------------------------------------------------------------------
+
+const char*
+ltoRemove()
+{
+    int err = unlink(cc_file);
+    if (-1 == err)
+    {
+        return strerror(errno);
+    }
+    return 0;
+}
+
+//-----------------------------------------------------------------------------------
+//
+//                      ltoLastDownloaded()
+//
+//-----------------------------------------------------------------------------------
+
+int
+ltoLastLoaded(int n, char* msg)
+{
+    struct stat lto_stat;
+    if (-1 == stat(cc_file, &lto_stat))
+    {
+        return sprintf(msg, "Can't find %s", cc_file);
+    }
+
+    struct tm* p = localtime(&lto_stat.st_mtime);
+    return strftime(msg, n, "LTO last loaded %x %X", p);
+}
+
+//------------------------------------------------------------------------------------
+//
+//                      ltoDownloadStart()
+//
+//------------------------------------------------------------------------------------
+
+const char*
+ltoDownloadStart()
+{
+    if (lto_downloading_flag)
+    {
+        return "Download in progress";
+    }
+    lto_read_init();
+
+    const char* lto_get = cc_lto_get;
+    const char* url     = cc_url;
+    const char* file    = cc_file;
+    const char* debug   = "+DEBUG";
+    // const char* sim     = "+SIM";
+    const char* sim     = 0;
+
+#if 1
+    printf("ltoDownloadStart()/%d URL %s  FILE %s  PROGRAM %s  %s\n",
+                            __LINE__, url, file, lto_get, debug);
+#endif
+
+    //  Make sure that lto_get is an executable.
+
+    struct stat st;
+    if (-1 == lstat(lto_get, &st))
+    {
+        fprintf(stderr, "omgui: lstat(%s) Error %d %s\n",
+                            lto_get, errno, strerror(errno));
+        return "Can't find lto_get program";
+    }
+
+    if (!(st.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)))
+    {
+        fprintf(stderr, "omgui: \"%s\" mode %o not executable\n",
+                    lto_get, st.st_mode);
+        return "lto_program is not executable";
+    }
+
+    int fd[2];
+    int err = pipe(fd);
+    if (err)
+    {
+        fprintf(stderr, "omgui: pipe() err %d %s\n", errno, strerror(errno));
+        return "Can't open pipe";
+    }
+
+    int pid = fork();
+    if (pid)
+    {
+        //--------------------------------------------------
+        //      We're the parent - connect child output
+        //      to GTK+ and then wait for input.
+        //--------------------------------------------------
+
+        close(fd[1]);                   // close the write side
+        lto_fd  = fd[0];
+        lto_pid = pid;
+        lto_cb_tag = gdk_input_add(lto_fd, GDK_INPUT_READ, lto_fd_read, 0);
+        return 0;
+    }
+
+    //--------------------------------------------------
+    // we're the child - exec the program.
+    //--------------------------------------------------
+
+#if 1
+    printf("<debug>=\"starting to execl(%s,%s,%s,%s,%s)\"\n",
+                            lto_get, url, file, debug, sim);
+
+    int opt = fcntl(fd[1], F_GETFL, 0);
+    if (-1 == opt)
+    {
+        fprintf(stderr,"<err>=fcntl(%d,F_GETFL,0) error %d %s\"\n",
+                    fd[1], errno, strerror(errno));
+    }
+    else
+    {
+        opt |= O_NONBLOCK;
+        opt = fcntl(fd[1], F_SETFL, opt);
+        if (-1 == opt)
+        {
+            fprintf(stderr,"<err>=fcntl(%d,F_SETFL,0x%x) error %d %s\"\n",
+                        fd[1], opt, errno, strerror(errno));
+        }
+    }
+#endif
+
+    // close(0);        // close stdin
+    close(1);           // close stdout
+    close(fd[0]);       // close the write side
+
+    int fd1 = dup(fd[1]);   // reopen stdout and stderr
+    if (fd1 != 1)
+    {
+        fprintf(stderr,"<err>=failed to reopen stdout %d %s\n",
+                    errno, strerror(errno));
+        exit(3);
+    }
+
+    close(2);               // close stderr
+    int fd2 = dup(fd[1]);   // to point to our pipe.
+    if (fd2 != 2)
+    {
+        fprintf(stderr, "<err>=failed to reopen stderr %d %s\n",
+                    errno, strerror(errno));
+        exit(3);
+    }
+
+    printf("<progress>=a\n");       // indicate we're alive
+
+    err = execl(lto_get, lto_get, url, file, debug, sim, 0);
+    printf("<err>=\"execl(%s,%s,%s,%s,%s) error %d %s\"\n",
+                lto_get, url, file, debug, sim,
+                errno, strerror(errno));
+    exit(3);
+    return "fork() and exec() failed";
+}
+
+//-----------------------------------------------------------------------------
+//
+//                      lto_parse_output()
+//
+//      Decode the lto_get process output.
+//
+//      Returns:
+//              0       Done.  Successfull.
+//              n < 0   Normal progress report.  Continue.
+//              n > 0   Error code.  Should stop.
+//
+//-----------------------------------------------------------------------------
+
+static int
+lto_parse_output(const char* buf)
+{
+    // printf("parse_output(%s) %d\n", buf, strlen(buf));
+    if (!strncmp(buf, "<done>=", 7))
+    {
+        int n;
+
+        sscanf(buf + 7, "%d", &n);
+        // printf("done - %d bytes\n", n);
+        return 0;
+    }
+
+    if (!strncmp(buf, "<percent>=", 10))
+    {
+        int n;
+
+        sscanf(buf + 10, "%d", &n);
+        // printf("percent =  %d%%\n", n);
+        lto_download_percent(n);
+        return -1;
+    }
+
+    if (!strncmp(buf, "<progress>=", 11))
+    {
+        char progress = buf[11];
+        // printf("progress = '%c'\n", progress);
+        lto_download_progress(progress);
+        return -2;
+    }
+
+    if (!strncmp(buf, "<err>=", 6))
+    {
+        const char* err = buf + 6;
+        // printf("error = %s\n", err);
+        lto_download_error(err);
+        return 1;
+    }
+
+    if (!strncmp(buf, "<debug>=", 8))
+    {
+        const char* dbg = buf + 8;
+        printf("debug = %s\n", dbg);
+        return -3;
+    }
+
+    printf("Unparsed lto output \"%s\"\n", buf);
+    return 2;
+}
+
+//-----------------------------------------------------------------------------
+//
+//              lto_read_output()
+//
+//      Read output of the lto_get process.
+//
+//      Returns:
+//              0       Done.  Successfull.
+//              n < 0   Normal progress report.  Continue.
+//              n > 0   Error code.  Should stop.
+//
+//-----------------------------------------------------------------------------
+
+static int  offset;
+static char buf[1024];
+
+static void
+lto_read_init()
+{
+    offset = 0;
+    buf[0] = 0;
+}
+
+static int
+lto_read_output(int fd)
+{
+    // printf("lto_read(%d,buf,%d)\n", fd, sizeof(buf) - offset); 
+    int n = read(fd, buf + offset, sizeof(buf) - offset);
+    if (n < 0)
+    {
+        // printf("lto_read(%d) error %d %s\n", n, errno, strerror(errno));
+        return 2;
+    }
+    else if (n > 0)
+    {
+        buf[n] = 0;
+        // printf("lto_read(%d,%d,%s)\n", fd, n, buf);
+    }
+    else
+    {
+        // printf("read(%d,%d)\n", fd, n);
+        return -4;
+    }
+    char* pEnd = buf + n + offset;
+    *pEnd = 0;
+
+    char* pNext;
+    for (char* p = buf; p < pEnd; p = pNext + 1)
+    {
+        pNext = strchr(p, '\n');
+        if (!pNext)
+        {
+            pNext  = pEnd;
+            offset = pNext - p;                 // printf("Offset %d\n", offset);
+            memcpy(buf, p, offset);
+            buf[offset] = 0;
+            break;
+        }
+        *pNext = 0;
+
+        int err = lto_parse_output(p);
+        if (err >= 0)
+        {
+            return err;
+        }
+    }
+    return -5;                  // Incomplete read.
+}
+
+static void
+lto_fd_read(gpointer data, gint source, GdkInputCondition cond)
+{
+    GtkWidget* label = GTK_WIDGET(data);
+    if (source != lto_fd)
+    {
+        lto_download_error("fd mismatch");
+        return;
+    }
+    if (GDK_INPUT_READ != cond)
+    {
+        lto_download_error("gtk read callback condition mismatch");
+        return;
+    }
+    int err = lto_read_output(lto_fd);
+
+    if (err >= 0)
+    {
+        // printf("omgui: lto_status %d\n", err);
+        // fflush(stdout);
+        lto_wait_for_stop();
+    }
+}
+
+//-----------------------------------------------------------------------------
+//
+//              lto_download_stop()
+//
+//      Disconnect the LTO_GET process from GTK+
+//
+//-----------------------------------------------------------------------------
+
+static void
+lto_wait_for_stop()
+{
+    const char* msg = ltoDownloadPidWait();
+    if (msg)
+    {
+        lto_download_error(msg);
+        if (lto_pid > 0)
+        {
+            printf("lto_wait_for_stop()/%d kill(%d,SIGKILL %d)\n",
+                                    __LINE__, lto_pid, SIGKILL);
+            kill(lto_pid, SIGKILL);
+        }
+    }
+    else
+    {
+        lto_download_error("LTO Download Done");
+    }
+    gdk_input_remove(lto_cb_tag);
+    close(lto_fd);
+    lto_fd = -1;
+}
+
+//-----------------------------------------------------------------------------
+//
+//              lto_download_stop()
+//
+//      Forcibly stop the LTO download.
+//
+//-----------------------------------------------------------------------------
+
+void
+lto_download_stop()
+{
+    if (lto_pid > 0)
+    {
+        printf("lto_download_stop()/%d kill(%d,SIGKILL %d)\n",
+                                __LINE__, lto_pid, SIGKILL);
+        kill(lto_pid, SIGKILL);
+        lto_wait_for_stop();
+    }
+}
+
+//-----------------------------------------------------------------------------
+//
+//                      ltoDownloadPidWait()
+//
+//      Wait for the LTO download PID to complete.
+//
+//      Returns:
+//              0       Done.  Successfull.
+//              msg     Some error message.
+//
+//-----------------------------------------------------------------------------
+
+static const char*
+ltoDownloadPidWait()
+{
+    int   stat = 0;
+    pid_t x    = waitpid(lto_pid, &stat, 0);                // WNOHANG will poll
+    if (x == lto_pid)
+    {
+        lto_downloading_flag = false;
+        lto_pid = 0;
+        lto_download_done();
+    }
+    else
+    {
+        fprintf(stderr, "omgui: %d = waitpid(%d) err %d %s\n",
+                x, lto_pid, errno, strerror(errno));
+    }
+    if (WIFEXITED(stat))
+    {
+        lto_download_done();
+        lto_downloading_flag = false;
+        lto_pid = 0;
+
+        int exit_code = WEXITSTATUS(stat);
+        fprintf(stderr, "omgui: %s exit code %d\n",
+                        cc_lto_get, exit_code);
+        if (exit_code) return "lto_get failed: abnormal exit";
+        return 0;
+    }
+    if (WIFSIGNALED(stat))
+    {
+        return "lto_get failed: signalled";
+    }
+    return "lto_get wait failed";
+}

Added: developers/olv/openmoko-agpsui2/src/lto_download.h
===================================================================
--- developers/olv/openmoko-agpsui2/src/lto_download.h	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/lto_download.h	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,24 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+extern const char* ltoRemove(void);
+extern int  ltoExpires(int* days, int* hours);
+extern int  ltoLastLoaded(int n, char* buf);
+extern const char* ltoDownloadStart();

Added: developers/olv/openmoko-agpsui2/src/main.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/main.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/main.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,152 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <glib/gstdio.h>
+#include "agps.h"
+
+GtkWidget* notebook_create(GtkWidget* window);
+
+extern GtkLabel* agpsLabel;
+extern void NMEA_MSG(const char* msg);
+
+void 
+button_on(GtkWidget *button, gboolean sensitive)
+{
+    gtk_widget_set_sensitive(button, sensitive);
+}
+
+void
+trace_arg(int argc, char** argv)
+{
+    FILE* f = fopen("omgui.trace", "a+");
+    int   i = 0;
+
+    fprintf(f, "\nCommand: ");
+    for (; i < argc; ++i)
+    {
+        fprintf(f, "\"%s\" ", argv[i]);
+        printf(      "%s ",   argv[i]);
+    }
+    fprintf(f, "\n");
+     printf(   "\n");
+    fclose(f);
+}
+
+void
+trace_env(char** envp)
+{
+    FILE* f = fopen("omgui.trace", "a+");
+    for (; *envp; ++envp)
+    {
+        fprintf(f, "env:  \"%s\"\n", *envp);
+    }
+    fclose(f);
+}
+
+const char* argv0;
+
+FILE *dump_nmea_fp;
+static int dump_nmea;
+int debug_all;
+static GOptionEntry entries[] = {
+	{ "debug-nmea", 'd', 0, G_OPTION_ARG_NONE, &dump_nmea, NULL, NULL },
+	{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &debug_all, NULL, NULL },
+	{ NULL }
+};
+
+int main(int argc, char** argv, char** envp)
+{
+    GtkWidget* window;
+    GtkWidget* label;
+    GtkWidget* button1;
+    GtkWidget* button2;
+    GtkWidget* vbox;
+    GtkWidget* table;
+
+    argv0 = argv[0];
+
+    // printf("%s/%d\n", __FILE__, __LINE__);
+
+    // trace_arg(argc, argv);
+    // trace_env(envp);
+
+    if (!g_thread_supported())
+    {
+        g_thread_init(NULL);
+    }
+
+    gdk_threads_init();
+    gtk_init(&argc, &argv);
+
+    {
+	    GOptionContext *context = g_option_context_new("gps");
+
+	    g_option_context_add_main_entries(context, entries, NULL);
+	    g_option_context_parse(context, &argc, &argv, NULL);
+	    g_option_context_free(context);
+
+	    if (debug_all)
+		    dump_nmea_fp = stdout;
+
+	    if (dump_nmea)
+	    {
+		    char name[128];
+		    time_t t;
+		    struct tm *tmp;
+		    int fd;
+
+		    if (g_chdir("/home/root") == 0)
+		    {
+			    strcpy(name, "nmea-");
+			    t = time(NULL);
+			    tmp = localtime(&t);
+
+			    strftime(name + 5, sizeof(name) - 5, "%m%d-%H%M", tmp);
+
+			    strcat(name, ".log");
+
+			    fd = open(name, O_CREAT | O_WRONLY | O_SYNC);
+			    if (fd >= 0)
+				    dump_nmea_fp = fdopen(fd, "w");
+		    }
+	    }
+    }
+    //--------------------------------------------------------------------------
+    //          top window
+    //--------------------------------------------------------------------------
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title(GTK_WINDOW (window), "AGPS Test Program");
+    gtk_window_set_default_size(GTK_WINDOW(window),480,640);
+    g_signal_connect(G_OBJECT(window), "delete_event", gtk_main_quit, NULL);
+
+    gtk_container_add(GTK_CONTAINER(window), notebook_create(window));
+
+    gtk_widget_show(window);
+
+    gdk_threads_enter();	 
+    gtk_main();
+    gdk_threads_leave();
+
+    return 0;
+}

Added: developers/olv/openmoko-agpsui2/src/nmea.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/nmea.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/nmea.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,321 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "nmea.h"
+
+static char delim[] = ",*";
+
+extern void page_SS_have_prn(int prn, int ss, int el, int az);
+extern void page_SS_use_prn (int prn);
+extern void page_SS_unuse_prns(void);
+extern void notebook_nmea_epoch(void);
+
+int GPGGA(char* str, struct nmea_gga* gga)
+{
+    char* ptr = str;
+    char* pptr;	
+    int i = 0;	
+    bool done = false;	
+
+    // g_printf("GGA(\"%s\")\n", str);
+
+    for (ptr = str; !done && ptr; ++ptr)
+    {
+        for (pptr = ptr; *ptr!=delim[0] && *ptr!=delim[1]; ++ptr)
+        {
+            if (!*ptr)
+            {
+                done = true;
+                break;
+            }		
+        }
+        *ptr = '\0';
+
+        switch(i)
+        {
+        default: break;
+        case 0: strncpy(gga->sentence,    pptr,  8); ++i; break;
+        case 1: strncpy(gga->time,        pptr, 16); ++i; break;
+        case 2: strncpy(gga->latitude,    pptr, 16); ++i; break;
+        case 3: strncpy(gga->la,          pptr,  4); ++i; break;
+        case 4: strncpy(gga->longitude,   pptr, 16); ++i; break;
+        case 5: strncpy(gga->lo,          pptr,  4); ++i; break;
+        case 6: strncpy(gga->fix_quality, pptr,  4); ++i; break;
+        case 7: strncpy(gga->nos,         pptr,  4); ++i; break;
+        case 8: strncpy(gga->hdop,        pptr,  8); ++i; break;
+        case 9: strncpy(gga->alme,        pptr,  8); ++i; break;
+        case 10: strncpy(gga->al,         pptr,  4); ++i; break;
+        case 11: strncpy(gga->hog,        pptr,  8); ++i; break;
+        case 12: strncpy(gga->ho,         pptr,  4); ++i; break;
+        case 13: strncpy(gga->tis,        pptr, 16); ++i; break;
+        case 14: strncpy(gga->DGPS,       pptr, 16); ++i; break;	
+        case 15: strncpy(gga->checksum,   pptr,  4); ++i; break;	
+        }
+    }
+    // g_printf("%d gga->time(\"%s\")\n", __LINE__, gga->time);
+    return 0;
+}
+
+int GPGSV(char* str, struct nmea_gsv* gsv)
+{
+    char* ptr = str;
+    char* pptr;
+    int i = 0;
+    int j = 0;
+    int k = 0;
+    bool done = false;
+    int checksum = 0;
+
+    // g_printf("\"%s\"", str);
+
+    for (ptr = str; !done && ptr; ++ptr)
+    {
+        for (pptr = ptr; *ptr!=delim[0] && *ptr!=delim[1]; ++ptr)
+        {
+            if (!*ptr)
+            {
+                done = true;
+                break;
+            }		
+        }
+        *ptr = '\0';
+
+        if (*ptr == delim[1])
+        {
+            checksum = 1;             
+        }
+
+        switch(i)
+        {
+        default: break;
+        case 0: strncpy(gsv->sentence, pptr, 8); ++i; break;      
+        case 1: strncpy(gsv->nose,     pptr, 4); ++i; break;
+        case 2: strncpy(gsv->sn,       pptr, 4); ++i; break;
+        case 3:	strncpy(gsv->nosa,     pptr, 4); ++i; break;
+        case 5: strncpy(gsv->checksum, pptr, 4); ++i; break;
+
+        case 4: strncpy(gsv->sate[j][k], pptr, 4);
+            if (++k >= 4)
+            {
+                int prn = atoi(gsv->sate[j][0]);
+                int el  = atoi(gsv->sate[j][1]);
+                int az  = atoi(gsv->sate[j][2]);
+                int CN0 = atoi(gsv->sate[j][3]);
+
+                // printf("%d) %s %s %s %s\n",
+                //         j,
+                //         gsv->sate[j][0], gsv->sate[j][1],
+                //         gsv->sate[j][2], gsv->sate[j][3]);
+                // printf("%d) prn %d  el %d  az %d  ss %d\n",
+                //             j, prn, el, az, CN0);
+                page_SS_have_prn(prn, CN0, el, az);
+
+                k = 0;                  // Start over with the
+                ++j;                    // ... next SV
+            }			
+            if (checksum)
+            {
+                gsv->n = j;                
+                i = 5;
+            }   
+            break;					
+        }
+    }
+    return 0;
+}
+
+int GPGSA(char* str, struct nmea_gsa* gsa)
+{
+    char* ptr;
+    char* pptr;	
+    int i = 0;	
+    int j = 0;
+    bool done = false;	
+    page_SS_unuse_prns();
+
+    // g_printf("\"%s\"", str);
+
+    for (ptr = str; !done && ptr; ++ptr)
+    {
+        for (pptr = ptr; *ptr!=delim[0] && *ptr!=delim[1]; ++ptr)
+        {
+            if (!*ptr)
+            {
+                done = true;
+                break;
+            }		
+        }
+        *ptr = '\0';
+
+        switch(i)
+        {
+        default: break;
+        case 0: strncpy(gsa->sentence, pptr, 8); ++i; break;      
+        case 1: strncpy(gsa->AM,       pptr, 4); ++i; break;
+        case 2: strncpy(gsa->mode,     pptr, 4); ++i; break;
+        case 4: strncpy(gsa->PDOP,     pptr, 8); ++i; break;
+        case 5: strncpy(gsa->HDOP,     pptr, 8); ++i; break;
+        case 6: strncpy(gsa->VDOP,     pptr, 8); ++i; break;			
+        case 7: strncpy(gsa->checksum, pptr, 4); ++i; break;
+        case 3:
+            if (j < 12)
+            {	
+                strncpy(gsa->id[j], pptr, 4);
+                j++;
+            }
+            else ++i;
+            break;
+        }
+    }
+    
+    gsa->n = 0;
+    for (i = 0; i < 12; ++i)
+    {
+        if (strlen(gsa->id[i]))
+        {
+            page_SS_use_prn(atoi(gsa->id[i]));
+            ++gsa->n;
+        }
+    }
+    notebook_nmea_epoch();
+
+    return 0;
+}
+
+void page_stats_fix_time(float ttf, float ttff);
+
+int PGLOR_FIX(char* str, struct nmea_lor* lor)
+{
+    bool done = false;	
+    int i = 0;	
+
+    lor->fixTime = -1.0;
+    lor->ttff    = -1.0;
+
+    char* pTTFF = strstr(str, ",TR,");
+    if (pTTFF && (1 != sscanf(pTTFF + 4, "%f", &lor->ttff)))
+    {
+        lor->ttff = -1.0;
+    }
+
+    for (char* ptr = str; !done && ptr; ++i, ++ptr)
+    {
+        char* pptr = ptr;	
+        for (; *ptr != delim[0] && *ptr != delim[1]; ++ptr)
+        {
+            if (!*ptr)
+            {
+                done = true;
+                break;
+            }		
+        }
+        *ptr = '\0';
+
+        if (2 == i)                 // Get the fix time.
+        {
+            if (1 != sscanf(pptr, "%f", &lor->fixTime))
+            {
+                lor->fixTime = -1.0;
+            }
+        }
+    }
+
+    // printf("PGLOR_FIX   ttff %f   ttf %f\n", lor->ttff, lor->fixTime);
+    page_stats_fix_time(lor->fixTime, lor->ttff);
+    return 0;
+}
+
+//      Show integration problems with the platform
+//      Skip the "$PGLOR,IGR," to collect the data up to "*"
+//      Skip the "$PGLOR,IGC," to collect the data up to "*"
+
+int PGLOR_IGR(char* str, struct nmea_lor* lor)
+{
+    char* c = 0;
+    int   ch = ' ';
+    if (strstr(str, ",IGR"))
+    {
+        ++lor->nIgr;
+        lor->igr[0] = 0;
+    }
+    c = strstr(str, "*");
+    if (c)
+    {
+        *c = 0;
+    }
+    str += 11;          // Skip the "$PGLOR,IGR,"
+
+    //  Replace ',' in the IGR messages by ' ' alternating with '='.
+    for (c = str; *c; ++c)
+    {
+        if (',' == *c)
+        {
+            *c = ch;
+            if (' ' == ch) ch = '=';
+            else           ch = ' ';
+        }
+        if ('.' == *c) *c = 'x';
+    }
+
+    strcat(lor->igr, str);
+    strcat(lor->igr, "\n\r");
+    // printf("PGLOR_IGR/%d \"%s\"\n", __LINE__, lor->igr);
+    return 0;
+}
+
+//      Get the firmware version number
+//      Skip the "$PGLOR,RID," to collect the data up to "*"
+
+int PGLOR_RID(char* str, struct nmea_lor* lor)
+{
+    char* c = 0;
+    c = strstr(str, "*");
+    if (c) *c = 0;      // Truncate the checksum "*XX\n\r"
+
+    str += 15;          // Skip the "$PGLOR,RID,GLL,"
+
+    //  Replace ',' in the message by '.'
+    for (c = str; *c; ++c)
+    {
+        if (',' == *c) *c = '.';
+    }
+    strcpy(lor->rid, str);
+    printf("PGLOR_RID/%d %s\n", __LINE__, lor->rid);
+    return 0;
+}
+
+//      The GLLIN has exited.
+
+int PGLOR_EXIT(char* str, struct nmea_lor* lor)
+{
+    // lor->exit = 1;
+    printf("PGLOR_EXIT/%d\n", __LINE__);
+    return 0;
+}
+
+// TODO:                Decode the RMC message.
+
+int GPRMC(char* str, struct nmea_rmc* rmc)
+{
+    return 0;
+}

Added: developers/olv/openmoko-agpsui2/src/nmea.h
===================================================================
--- developers/olv/openmoko-agpsui2/src/nmea.h	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/nmea.h	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef NMEA_H_
+#define NMEA_H_
+
+#ifndef NMEA_H_
+#include "nmea.h"
+#endif 
+
+#define GGA "$GPGGA"
+#define RMC "$GPRMC"
+#define GSV "$GPGSV"
+#define GSA "$GPGSA"
+#define LOR "$PGLOR"
+
+struct nmea_gga {
+	char sentence[8];
+	char time[16];
+	char latitude[16];
+	char la[4];
+	char longitude[16];
+	char lo[4];
+	char fix_quality[4];
+	char nos[4];
+	char hdop[8];
+	char alme[8];
+	char al[4];
+	char hog[8];
+	char ho[4];
+	char tis[16];
+	char DGPS[16];
+	char checksum[4];
+};
+
+struct nmea_rmc {
+	char sentence[8];
+};
+
+struct nmea_gsv {
+	char sentence[8];
+	char nose[4];
+	char sn[4];
+	char nosa[4];
+	char sate[4][4][4];
+	char checksum[4];
+	int  n;
+};
+
+struct nmea_gsa {
+	char sentence[8];
+	char AM[4];
+	char mode[4];
+	char id[12][4];
+	char PDOP[8];
+	char HDOP[8];
+	char VDOP[8];
+	char checksum[4];
+	int  n;
+};
+
+struct nmea_lor {
+	int  nIgr;
+        float fixTime;
+        float ttff;
+	char sentence[8];
+	char rid[32];
+	char igr[80*5];
+};
+
+int GPGGA(char* str, struct nmea_gga* gga);
+int GPGSV(char* str, struct nmea_gsv* gsv);
+int GPGSA(char* str, struct nmea_gsa* gsa);
+int GPRMC(char* str, struct nmea_rmc* rmc);
+int PGLOR_IGR(char* str, struct nmea_lor* lor);
+int PGLOR_RID(char* str, struct nmea_lor* lor);
+int PGLOR_FIX(char* str, struct nmea_lor* lor);
+int PGLOR_EXIT(char* str, struct nmea_lor* lor);
+
+#endif

Added: developers/olv/openmoko-agpsui2/src/notebook.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/notebook.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/notebook.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,451 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PAGE_LTO
+#define PAGE_MAP
+#define PAGE_GSM
+#define PAGE_STRESS
+// #define PAGE_ADD
+#define PAGE_RFI
+
+#ifndef  PAGE_STRESS_H__                // {
+#include "page_stress.h"
+#endif                                  // }
+
+extern const char* argv0;
+GtkWidget* page_main_create (GtkWidget* window);
+GtkWidget* page_SS_create   (GtkWidget* window);
+GtkWidget* page_AZ_create   (GtkWidget* window);
+GtkWidget* page_speed_create(GtkWidget* window);
+GtkWidget* page_stats_create(GtkWidget* window);
+GtkWidget* page_stress_create(GtkWidget* window);
+GtkWidget* page_LTO_create(GtkWidget* window);
+GtkWidget* page_MAP_create(GtkWidget* window);
+
+#ifdef  PAGE_RFI
+GtkWidget* page_bt_create(GtkWidget* window);
+GtkWidget* page_audio_create(GtkWidget* window);
+GtkWidget* page_rfi_create(GtkWidget* window);
+#endif
+
+#ifdef  PAGE_GSM
+GtkWidget* page_GSM_create(GtkWidget* window);
+#endif
+
+#ifdef  PAGE_ADD
+GtkWidget* page_ADD_create(GtkWidget* window);
+#endif
+
+GtkWidget* page_log_create(GtkWidget* window);
+
+static GtkWidget* notebook = 0;
+
+static void
+on_notebook_3(GtkWidget *widget, gint arg1, gpointer data)
+{
+    // printf("%s/%d signal %s\n", __FILE__, __LINE__, (char*) data);
+}
+
+static void
+on_notebook_4(GtkWidget *widget, gint arg1, guint page_num, gpointer data)
+{
+    // printf("%s/%d signal %s  page %d\n",
+    //                     __FILE__, __LINE__,
+    //                     (char*) data, page_num);
+}
+
+static void
+notebook_callback(int cb_i, const char* signal)
+{
+    GCallback cb = G_CALLBACK(on_notebook_3);
+    if (4 == cb_i) cb = G_CALLBACK(on_notebook_4);
+
+    g_signal_connect(G_OBJECT(notebook), signal, cb, (gpointer) signal);
+}
+
+//      Bitmap for the pages to be created:
+
+enum
+{
+        ALLOW_MAIN      = 0x01,            // part of minimum
+        ALLOW_SS        = 0x02,            // part of minimum
+        ALLOW_AZ        = 0x04,            // part of minimum
+        ALLOW_SPEED     = 0x08,
+        ALLOW_STATS     = 0x10,
+        ALLOW_STRESS    = 0x20,
+        ALLOW_LTO       = 0x40,        // part of minimum
+        ALLOW_MAP       = 0x80,        // part of minimum
+        ALLOW_ADD       = 0x100,
+
+        ALLOW_MINIMUM   = (ALLOW_MAP+ALLOW_MAIN+ALLOW_SS+ALLOW_AZ)
+};
+
+static int notebook_page_mask = 0;
+
+static const char*
+page_names[] =
+{
+    "main",
+    "signal strength",
+    "azimuth",
+    "dials",
+    "test",
+    "stats",
+    "LTO",
+    "plot"
+};
+
+#ifndef DIM
+#define DIM(x)          (sizeof(x)/sizeof(*x))
+#endif
+
+static const char*
+notebook_page_name(int i)
+{
+    // printf("%s/%d notebook_page_name(%d) %d  ",
+    //             __FILE__, __LINE__, i, DIM(page_names));
+    if (i >= 0 && i < DIM(page_names))
+    {
+        // printf("%s\n", page_names[i]);
+        return page_names[i];
+    }
+    // printf(",<null>\n");
+    return 0;
+}
+
+GtkWidget*
+notebook_create(GtkWidget* window)
+{
+    // printf("%s/%d\n", __FILE__, __LINE__);
+    notebook = gtk_notebook_new();
+    GtkWidget* label;
+    gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
+
+    int page_mask = 0;
+    int nPages = 0;
+
+    if (argv0 && *argv0)
+    {
+        const char key[] = {"-pagemask-"};
+        const char* p = strstr(argv0,key);
+        if (p)
+        {
+            p += strlen(key);
+            page_mask = strtol(p, 0, 16);
+        }
+    }
+    page_mask |= ALLOW_MINIMUM;
+    notebook_page_mask = page_mask;
+
+    if (page_mask & ALLOW_MAIN)
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        label = gtk_label_new("run");
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+                                 page_main_create(window), label);
+    }
+
+    if (page_mask & ALLOW_SS)
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        label = gtk_label_new("SS");
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+                    page_SS_create(window), label);
+    }
+
+    if (page_mask & ALLOW_AZ)
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        label = gtk_label_new("AZ");
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+                    page_AZ_create(window), label);
+    }
+
+    if (page_mask & ALLOW_SPEED)
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        label = gtk_label_new("dial");
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+                    page_speed_create(window), label);
+    }
+
+    if (page_mask & ALLOW_STATS)
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        label = gtk_label_new("stat");
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), 
+                    page_stats_create(window), label);
+    }
+
+#ifdef PAGE_LTO
+    if (page_mask & ALLOW_LTO)
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        label = gtk_label_new("LTO");
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+                        page_LTO_create(window), label);
+    }
+#endif
+
+#ifdef PAGE_MAP
+    if (page_mask & ALLOW_MAP)
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+                                 page_MAP_create(window),
+                                 gtk_label_new("plot")    );
+    }
+#endif
+
+#ifdef PAGE_STRESS
+    if (page_mask & ALLOW_STRESS)
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        label = gtk_label_new("test");
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+                        page_stress_create(window), label);
+    }
+#endif
+
+#ifdef PAGE_ADD
+    if (page_mask & ALLOW_ADD)
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+                        page_ADD_create(window), gtk_label_new("ADD"));
+    }
+#endif
+
+    {
+        // printf("%s/%d\n", __FILE__, __LINE__);
+        ++nPages;
+        label = gtk_label_new("Log");
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+                    page_log_create(window), label);
+    }
+
+    if (nPages > 7)
+    {
+        gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
+
+        notebook_callback(3, "change-current-page");
+        notebook_callback(3, "focus-tab");
+        notebook_callback(3, "move-focus-out");
+//      notebook_callback(4, "page-added");                // in GTK+ v2.10 and later
+//      notebook_callback(4, "page-removed");              // in GTK+ v2.10 and later
+//      notebook_callback(4, "page-reordered");            // in GTK+ v2.10 and later
+//      notebook_callback(4, "reorder-tab");               // in GTK+ v2.10 and later
+        notebook_callback(3, "select-page");
+        notebook_callback(4, "switch-page");
+
+    }
+    gtk_widget_show(notebook);
+
+    // printf("%s/%d\n", __FILE__, __LINE__);
+    return notebook;
+}
+
+static bool b_exposedMN = false;        // Main page
+static bool b_exposedSS = false;        // Signal strength
+static bool b_exposedAZ = false;        // Azimuth
+static bool b_exposedSP = false;        // Speed
+static bool b_exposedST = false;        // Stats
+static bool b_exposedRR = false;        // Stress
+static bool b_exposedLT = false;        // LTO
+static bool b_exposedMP = false;        // Map
+
+bool exposedMN() { return b_exposedMN; }
+bool exposedSS() { return b_exposedSS; }
+bool exposedAZ() { return b_exposedAZ; }
+bool exposedSP() { return b_exposedSP; }
+bool exposedST() { return b_exposedST; }
+bool exposedRR() { return b_exposedRR; }
+bool exposedLT() { return b_exposedLT; }
+bool exposedMP() { return b_exposedMP; }
+
+extern void page_main_done();
+extern void page_SS_done();
+extern void page_AZ_done();
+extern void page_speed_done();
+extern void page_stats_done();
+extern void page_stress_done();
+extern void page_LTO_done();
+extern void page_MAP_done();
+
+void
+notebook_nmea_epoch(void)
+{
+#if 0
+    printf("notebook_nmea_epoch() %s%s%s%s%s\n",
+                    (exposedMN()) ? "main" : "",
+                    (exposedSS()) ? "SS" : "",
+                    (exposedAZ()) ? "AZ" : "",
+                    (exposedSP()) ? "speed" : "",
+                    (exposedST()) ? "stats" : "",
+                    (exposedST()) ? "LTO" : "",
+                    (exposedMP()) ? "MAP" : "",
+                    (exposedRR()) ? "stress" : "");
+#endif
+    if (exposedMN()) page_main_done();
+    if (exposedSS()) page_SS_done();
+    if (exposedAZ()) page_AZ_done();
+    if (exposedSP()) page_speed_done();
+    if (exposedST()) page_stats_done();
+    if (exposedRR()) page_stress_done();
+    if (exposedLT()) page_LTO_done();
+    if (exposedMP()) page_MAP_done();
+}
+
+void
+notebook_expose(const char* pageName)
+{
+    // printf("notebook_expose(%s)\n", pageName);
+    b_exposedMN = false;
+    b_exposedSS = false;
+    b_exposedAZ = false;
+    b_exposedSP = false;
+    b_exposedST = false;
+    b_exposedRR = false;
+    b_exposedLT = false;
+    if (!strcmp("MN", pageName)) b_exposedMN = true;
+    if (!strcmp("SS", pageName)) b_exposedSS = true;
+    if (!strcmp("AZ", pageName)) b_exposedAZ = true;
+    if (!strcmp("SP", pageName)) b_exposedSP = true;
+    if (!strcmp("ST", pageName)) b_exposedST = true;
+    if (!strcmp("RR", pageName)) b_exposedRR = true;
+    if (!strcmp("LT", pageName)) b_exposedLT = true;
+    if (!strcmp("MP", pageName)) b_exposedMP = true;
+}
+
+void 
+notebook_report_header(FILE* f, const char* msg)
+{
+    fprintf(f,
+        "\n"
+        "\n"
+        "                          %s Page\n"
+        "-------------------------------------------------------------------\n",
+        msg);
+}
+#define HDR(m)          notebook_report_header(f,m)
+
+const char* page_main_omgui_version(void);
+
+void 
+notebook_report_header(FILE* f)
+{
+    time_t t = time(0);
+    fprintf(f,
+        "\n"
+        "     %s Report\n"
+        "     Date:   %s\n"
+        "\n"
+        "                          Summary\n"
+        "-------------------------------------------------------------------\n"
+        "Pages enabled are %x:\n",
+
+        page_main_omgui_version(),
+        ctime(&t),
+        notebook_page_mask);
+
+    int page_count = 0;
+    for (int bit = 0; bit < 32; ++bit)
+    {
+        const char* page_name = notebook_page_name(bit);
+        if (page_name && ((1L << bit) & notebook_page_mask))
+        {
+            if (page_count > 3)
+            {
+                page_count = 0;
+                fprintf(f, ",\n");
+            }
+            fprintf(f, "%s      %s",
+                (page_count) ? "," : "", page_name);
+            ++page_count;
+        }
+    }
+    if (page_count) fprintf(f, "\n");
+}
+
+void 
+notebook_report_trailer(FILE* f)
+{
+}
+
+extern void page_main_report(FILE* f);
+extern void page_SS_report(FILE* f);
+extern void page_AZ_report(FILE* f);
+extern void page_speed_report(FILE* f);
+extern void page_stats_report(FILE* f);
+extern void page_stress_report(FILE* f);
+extern void page_LTO_report(FILE* f);
+extern void page_map_report(FILE* f);
+extern void page_RFI_report(FILE* f);
+extern void page_audio_report(FILE* f);
+extern void page_BT_report(FILE* f);
+extern void page_GSM_report(FILE* f);
+extern void page_ADD_report(FILE* f);
+
+void
+notebook_report(FILE* f)
+{
+    int page_mask = notebook_page_mask;
+    notebook_report_header(f);
+
+    if (page_mask & ALLOW_MAIN ) HDR("Main"           ), page_main_report (f);
+    if (page_mask & ALLOW_SS   ) HDR("Signal Strength"), page_SS_report   (f);
+    if (page_mask & ALLOW_AZ   ) HDR("Azimuth"        ), page_AZ_report   (f);
+    // if (page_mask & ALLOW_SPEED) HDR("Dials"          ), page_speed_report(f);
+    if (page_mask & ALLOW_STATS) HDR("Statistics"     ), page_stats_report(f);
+#ifdef PAGE_LTO
+    if (page_mask & ALLOW_LTO) HDR("LTO"), page_LTO_report(f);
+#endif
+#ifdef PAGE_MAP
+    if (page_mask & ALLOW_MAP) HDR("Plot"), page_map_report(f);
+#endif
+#ifdef PAGE_STRESS
+    if (page_mask & ALLOW_STRESS) HDR("Test"), page_stress_report(f);
+#endif
+#ifdef PAGE_GSM
+    // if (page_mask & ALLOW_GSM) HDR("GSM"), page_GSM_report(f);
+#endif
+#ifdef PAGE_ADD
+    // if (page_mask & ALLOW_ADD) HDR("ADD"), page_ADD_report(f);
+#endif
+#ifdef PAGE_RFI
+    // if (page_mask & ALLOW_RFI  ) HDR("RFI"      ), page_RFI_report  (f);
+    // if (page_mask & ALLOW_AUDIO) HDR("Audio"    ), page_audio_report(f);
+    // if (page_mask & ALLOW_BT   ) HDR("BlueTooth"), page_BT_report   (f);
+#endif
+    notebook_report_trailer(f);
+}

Added: developers/olv/openmoko-agpsui2/src/page_AZ.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_AZ.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_AZ.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,443 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <string.h>
+#include "agps.h"
+#include "sv_bar.h"
+
+void notebook_expose(const char* pageName);
+
+static GtkDrawingArea* AZ;
+static GdkPixmap*      AZ_PIX = 0;
+static PangoLayout*    AZ_text;
+
+static GdkGC* blue_gc = 0;
+static GdkGC* grey_gc = 0;
+
+extern GdkGC* alloc_color(GdkPixmap* pm, const char* color);
+
+enum
+{
+        MAX_AZ_SEGMENTS = 22
+};
+
+static GdkSegment az_lines[MAX_AZ_SEGMENTS];
+static int        nAzLines = 0;
+
+static void
+AZ_add_line(int x0, int y0, int x1, int y1)
+{
+    if (nAzLines >= MAX_AZ_SEGMENTS)
+    {
+        // printf("az_add_line(%d,%d  %d,%d) discarded %d\n",
+        //             x0, y0, x1, y1, nAzLines);
+        return;
+    }
+    // printf("az_add_line(%d,%d  %d,%d) %d\n",
+    //                 x0, y0, x1, y1, nAzLines);
+    GdkSegment& s = az_lines[nAzLines++];
+    s.x1 = x1;
+    s.y1 = y1;
+    s.x2 = x0;
+    s.y2 = y0;
+}
+
+// #define DEBUG
+
+#ifdef  DEBUG
+static void
+debugGC_(int line)
+{
+    printf("%d) blue_gc 0x%x  grey_gc 0x%x  AZ_PIX 0x%x\n",
+                line, blue_gc, grey_gc, AZ_PIX);
+    fflush(stdout);
+}
+#define debugGC()       debugGC_(__LINE__)
+#else
+#define debugGC()
+#endif
+
+bool showTrack = false;
+
+static void
+on_clicked_show_sv_track(GtkWidget* w, gpointer data)
+{
+    const char* text = "Show Track";
+    if (showTrack)
+    {
+        text = "Disable Track";
+    }
+    gtk_button_set_label(GTK_BUTTON(w), text);
+    showTrack = !showTrack;
+}
+
+static void
+AZ_alloc_colors()
+{
+    if (!AZ_PIX) return;
+    if (!blue_gc) blue_gc = alloc_color(AZ_PIX, "Blue");
+    if (!grey_gc) grey_gc = alloc_color(AZ_PIX, "SlateGrey");
+}
+
+static void
+AZ_clear()
+{
+    if (!AZ_PIX) return;
+    GtkWidget* w = GTK_WIDGET(AZ);
+    gdk_draw_rectangle(AZ_PIX, w->style->white_gc, TRUE,
+                       0, 0,
+                       w->allocation.width,
+                       w->allocation.height);
+}
+
+static gboolean
+configure_AZ_event(GtkWidget* w, GdkEventConfigure* event)
+{
+    debugGC();
+    if (AZ_PIX)
+    {
+        g_object_unref(AZ_PIX);
+    }
+
+    //--------------------------------------------------------------------------
+    //          pixmap
+    //--------------------------------------------------------------------------
+    AZ_PIX = gdk_pixmap_new(w->window,
+                            w->allocation.width,
+                            w->allocation.height, -1);
+    AZ_clear();
+    debugGC();
+    return TRUE;
+}
+
+static gboolean
+expose_AZ_event(GtkWidget* w, GdkEventExpose* event)
+{
+    notebook_expose("AZ");
+    if (AZ_PIX)
+    {
+        GdkRectangle& a = event->area;
+        gdk_draw_drawable(w->window,
+                      w->style->fg_gc[GTK_WIDGET_STATE(w)],
+                      AZ_PIX, a.x, a.y, a.x, a.y, a.width, a.height);
+    }
+    return FALSE;
+}
+
+extern GdkGC* page_SS_getGC(bool used);
+
+static GdkGC*
+getGC(bool used)
+{
+    AZ_alloc_colors();
+    GdkGC*    gc = grey_gc;
+    if (used) gc = blue_gc;
+    if (!gc)  gc = GTK_WIDGET(AZ)->style->black_gc;
+    return gc;
+}
+
+enum
+{
+    CENTER_XY = 3,
+    CENTER_X  = 1,
+    CENTER_Y  = 2,
+    CENTER_NONE = 0,
+
+    ALIGN_BOTTOM = 16,
+    ALIGN_RIGHT  = 32
+};
+
+static int
+AZ_draw_text(int x, int y, const char* t,
+                int center = CENTER_XY, GdkGC* gc = 0)
+{
+    int w = 0;
+    int h;
+
+    if (!gc) gc = getGC(false);
+    pango_layout_set_text(AZ_text, t, -1);
+    pango_layout_get_pixel_size(AZ_text, &w, &h);
+
+    if (center)
+    {
+        if      (center & CENTER_X    ) x -= w/2;
+        else if (center & ALIGN_RIGHT ) x -= w;
+        if      (center & CENTER_Y    ) y -= h/2;
+        else if (center & ALIGN_BOTTOM) y -= h;
+    }
+
+    // printf("AZ_draw_text(%d,%d,\"%s\", %d)\n", x, y, t, center);
+    gdk_draw_layout(AZ_PIX, gc, x, y, AZ_text);
+
+    return w;
+}
+
+static void
+AZ_draw_circle(int r, bool drawText = true)
+{
+    GdkGC* gc = getGC(false);
+
+    int radius = SV_bar::scale_radius(r);
+    int x = LARGE_WINDOW_WIDTH/2 - radius;
+    int y = x;
+    int width  = radius * 2;
+    int height = width;
+    int arc0 = 0;
+    int arcN = 360 * DEGREE_64;
+    gdk_draw_arc(AZ_PIX, gc, FALSE,
+                x, y,                 // starting point
+                width, height,
+                arc0, arcN);
+
+    if (drawText)
+    {
+        char elevation[4];
+        sprintf(elevation, "%d", r);
+        AZ_draw_text(x, LARGE_WINDOW_WIDTH/2, elevation);
+    }
+}
+
+static void
+AZ_draw_radial(int theta, int radius, bool drawText)
+{
+    GdkGC* gc = getGC(false);
+
+    SV_bar r;
+    r.el = radius;
+    r.az = theta;
+
+    int x0;
+    int y0;
+    r.get_xy(x0, y0);
+
+    y0  = LARGE_WINDOW_WIDTH/2 - y0;
+    x0 += LARGE_WINDOW_WIDTH/2;
+
+    int x1;
+    int y1;
+    r.el = 0;
+    r.get_xy(x1, y1);
+
+    y1  = LARGE_WINDOW_WIDTH/2 - y1;
+    x1 += LARGE_WINDOW_WIDTH/2;
+
+    // if (drawText)
+    //    printf("radial(%d,%d) x1,y1 = {%d,%d}\n", theta, radius, x1, y1);
+
+    if (drawText)
+    {
+        r.el = -8;
+        r.get_xy(x1, y1);
+        y1  = LARGE_WINDOW_WIDTH/2 - y1;
+        x1 += LARGE_WINDOW_WIDTH/2;
+
+        char str[8];
+        sprintf(str, "%d", theta);
+        AZ_draw_text(x1, y1, str);
+    }
+    else
+    {
+        AZ_add_line(x0, y0, x1, y1);
+    }
+}
+
+static void
+AZ_draw_sv(SV_bar& sv, bool drawDot)
+{
+    int yy;
+    int xx;
+    sv.get_xy(xx, yy);
+
+    yy  = LARGE_WINDOW_WIDTH/2 - yy;
+    xx += LARGE_WINDOW_WIDTH/2;
+
+    char prn[4];
+    sprintf(prn, "%d", sv.prn);
+
+    GdkGC* gc = getGC(sv.use);
+
+    // Get the text width.
+    int w;
+    int h;
+    pango_layout_set_text(AZ_text, prn, -1);
+    pango_layout_get_pixel_size(AZ_text, &w, &h);
+
+    //----------------------------------------------
+    //          Put a circle down first
+    //
+    //  SV used:    dark blue circle
+    //  SV unused:  light grey circle
+    //----------------------------------------------
+    if (h > w) w = h;                   // w = max(w,h)
+    int radius = 3 + w/2;
+    if (drawDot)
+    {
+        gdk_draw_arc(AZ_PIX, gc, TRUE,
+                    xx-radius, yy-radius-1,
+                    radius*2, radius*2,
+                    0, 360 * DEGREE_64);
+    }
+    else
+    {
+        //----------------------------------------------
+        //          Draw the SV number on the dot
+        //
+        //  SV used:    white text
+        //  SV unused:  black text
+        //----------------------------------------------
+        gc = GTK_WIDGET(AZ)->style->black_gc; 
+        if (sv.use) gc = GTK_WIDGET(AZ)->style->white_gc; 
+        AZ_draw_text(xx, yy, prn, CENTER_XY, gc);
+    }
+
+    // printf("AZ_draw_sv(%d   el %d    az %d) at %d,%d\n",
+    //              sv.prn, sv.el, sv.az, xx, yy);
+}
+
+static void
+AZ_draw_svs()
+{
+    if (!AZ_PIX) return;
+    if (!showTrack)
+    {
+        AZ_clear();
+    }
+
+    int f = LARGE_WINDOW_WIDTH;
+    int h = f/2;
+    int fw = FONT_WIDTH;
+    int fh = FONT_HEIGHT;
+
+    static bool been_here = false;
+    if (!been_here)
+    {
+        been_here = true;
+
+        AZ_add_line(fw,h,  f-fw,h);            // horizontal line
+        AZ_add_line(h,fh,  h,f-fh);            // vertical   line
+        for (int theta = 15; theta < 360; theta += 15)
+        {
+            int  r    = 44;
+            switch (theta)
+            {
+            default: break;
+            case 90: case 180: case 270: continue;
+            case 45: case 45 + 90: case 45 + 180: case 45 + 270:
+                r    = 74;
+                break;
+            }
+            AZ_draw_radial(theta, r, false);
+        }
+    }
+
+    GdkGC* gc = getGC(false);
+
+    gdk_draw_segments(AZ_PIX, gc, az_lines, nAzLines);
+    AZ_draw_radial(45    , 74, true);
+    AZ_draw_radial(45+ 90, 74, true);
+    AZ_draw_radial(45+180, 74, true);
+    AZ_draw_radial(45+270, 74, true);
+
+    AZ_draw_circle(0, false);
+    AZ_draw_circle(15);
+    AZ_draw_circle(45);
+    AZ_draw_circle(75);
+
+    AZ_draw_text(h, 0, "N", CENTER_X,                gc);
+    AZ_draw_text(h, f, "S", CENTER_X | ALIGN_BOTTOM, gc);
+    AZ_draw_text(f, h, "E", CENTER_Y | ALIGN_RIGHT,  gc);
+    AZ_draw_text(0, h, "W", CENTER_Y,                gc);
+
+    // Draw all the dots.
+    // Then draw all the numbers.
+    for (int b = 0; b < SV_bar::nSS; ++b) AZ_draw_sv(bars[b], true);
+    for (int b = 0; b < SV_bar::nSS; ++b) AZ_draw_sv(bars[b], false);
+
+    gtk_widget_queue_draw_area(GTK_WIDGET(AZ), 0, 0,
+                               PIXMAP_WIDTH, PIXMAP_WIDTH);
+}
+
+void
+page_AZ_done()
+{
+    AZ_draw_svs();
+}
+
+GtkWidget*
+page_AZ_create(GtkWidget* window)
+{
+    //--------------------------------------------------------------------------
+    //          table
+    //--------------------------------------------------------------------------
+    GtkWidget* table = gtk_table_new(14, 2, TRUE);
+
+    //--------------------------------------------------------------------------
+    //          label
+    //--------------------------------------------------------------------------
+    GtkWidget* label = gtk_label_new("Satellite Position");
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 0, 1);
+    gtk_widget_show(label);
+
+    AZ_text = gtk_widget_create_pango_layout(label, "");
+
+    //--------------------------------------------------------------------------
+    //          window for the satellite position
+    //--------------------------------------------------------------------------
+    GtkWidget* w  = gtk_drawing_area_new();
+    AZ = GTK_DRAWING_AREA(w);
+    gtk_drawing_area_size(AZ, PIXMAP_WIDTH, PIXMAP_WIDTH);
+
+    gtk_signal_connect(GTK_OBJECT(w), "configure_event",
+                    G_CALLBACK(configure_AZ_event), w);
+
+    gtk_signal_connect(GTK_OBJECT(w), "expose_event",
+                    G_CALLBACK(expose_AZ_event), w);
+
+    gtk_widget_set_events(w, GDK_EXPOSURE_MASK);
+    gtk_table_attach_defaults(GTK_TABLE (table), w, 0, 2, 1, 12);
+    gtk_widget_show(w);
+
+    //--------------------------------------------------------------------------
+    //          Show SV track
+    //--------------------------------------------------------------------------
+    GtkWidget* button = gtk_button_new_with_label("Show Track");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_show_sv_track), button);
+    gtk_table_attach_defaults(GTK_TABLE(table), button, 1, 2, 13, 14);
+    gtk_widget_show(button);
+
+    gtk_widget_show(table);
+    return table;
+}
+
+void
+page_AZ_report(FILE* f)
+{
+    for (int b = 0; b < SV_bar::nSS; ++b)
+    {
+        SV_bar& sv = bars[b];
+        fprintf(f, "PRN %2d  Elevation %2d   Azimuth %3d  %s\n",
+                sv.prn, sv.el, sv.az, (sv.use) ? " " : " unused");
+    }
+}

Added: developers/olv/openmoko-agpsui2/src/page_LTO.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_LTO.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_LTO.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,607 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "agps.h"
+#include "sv_bar.h"
+#include "lto_download.h"
+#include "liblto.h"             // Actual LTO library code from GL.
+
+static GdkGC* blue_gc = 0;
+static GdkGC* grey_gc = 0;
+
+static GtkDrawingArea* LTO;
+static GdkPixmap*      LTO_PIX = 0;
+static PangoLayout*    LTO_text;
+
+extern "C" void page_lto_file_change();
+
+extern void notebook_expose(const char* pageName);
+
+static void lto_set_download_text(const char* msg);
+static void lto_redraw();
+static void lto_pixmap_update();
+static void lto_draw_percent(bool age, int percent);
+
+GtkLabel* LTO_label;
+GtkLabel* LTO_age_label;
+
+int lto_age_percent = 0;
+static char lto_download_progress_ = ' ';
+static int  lto_download_percent_  =   0;
+static bool lto_file_changed = false;
+static void lto_file_lease(bool getLease);
+
+static void
+lto_report(FILE* f)
+{
+    char msg[128];
+    int hours = 0;
+    const char* ltoFile = "/home/root/gpsd/lto2.dat";
+    const char* err = NULL; /*ltoGetExpiration( ltoFile, &hours,
+                                        msg, sizeof(msg));*/
+    const char* report = err;
+    if (!report) report = msg;
+
+    if (f) fprintf(f, "%s\n", report);
+    else   gtk_label_set_text(LTO_age_label, report);
+
+    printf("%s = ltoGetExpiration(%s, %d, %s)\n",
+                (err) ? err : "OK", 
+                ltoFile,
+                hours,
+                msg);
+
+    if (err)
+    {
+        lto_age_percent = 0;
+    }
+    else
+    {
+        const int max_hours = 7 * 24;           // Assume 7-day LTO.
+        int percent = hours * 100;
+
+        percent += max_hours/2;
+        percent /= max_hours;
+
+        lto_age_percent = percent;
+        printf("Percent %d\n", lto_age_percent);
+    }
+
+    ltoLastLoaded(sizeof(msg), msg);
+
+    if (f) fprintf(f, "%s\nLTO useful for 7 days x %d%%", msg, lto_age_percent);
+    else   gtk_label_set_text(LTO_label, msg);
+}
+
+//------------------------------------------------------------------------------
+//
+//      Update a label with the sad news
+//
+//------------------------------------------------------------------------------
+
+void
+lto_download_error(const char* msg)
+{
+    gtk_label_set_text(LTO_label, msg);
+}
+
+//------------------------------------------------------------------------------
+//
+//      Update the LTO progress message and the.
+//      LTO percentage bar.
+//
+//------------------------------------------------------------------------------
+
+static void
+lto_draw_download_progress()
+{
+    char buf[64];
+    sprintf(buf, "Download %d%% complete %c.",
+                                lto_download_percent_, lto_download_progress_);
+    lto_set_download_text(buf);
+    lto_draw_percent(false, lto_download_percent_);
+}
+
+void
+lto_download_progress(char progress)
+{
+    lto_download_progress_ = progress;
+    lto_redraw();
+}
+
+void
+lto_download_percent(int n)
+{
+    lto_download_percent_ = n;
+    lto_redraw();
+}
+
+static void
+on_clicked_factory_reset(GtkWidget* w, gpointer d)
+{
+    const char* msg = ltoRemove();
+    if (!msg) msg = "Reset done";
+    lto_download_error(msg);
+    lto_report(0);
+    lto_redraw();
+}
+
+static GdkGC* 
+getGC(bool used)
+{
+    GdkGC* gc = grey_gc;
+    if (used)
+    {
+        gc = blue_gc;                   // used SV is colored blue
+    }
+    if (!gc)
+    {
+        gc = GTK_WIDGET(LTO)->style->black_gc;
+    }
+    return gc;
+}
+
+static void
+lto_set_download_text(const char* msg)
+{
+    int x = 20;
+    int y = 85;
+
+    pango_layout_set_text(LTO_text, msg, -1);
+    gdk_draw_layout(LTO_PIX, getGC(false), x, y, LTO_text);
+
+    // printf("LTO_set_download [%d,%d] %s\n", x, y, msg);
+}
+
+extern void lto_download_stop();
+bool downloading = false;
+GtkButton* lto_download_button = 0;
+
+void
+lto_download_done()
+{
+    downloading = false;
+    gtk_button_set_label(lto_download_button, "Start Download");
+    lto_report(0);
+}
+
+static void
+on_clicked_start_download(GtkWidget* w, gpointer d)
+{
+    // printf("clicked download %d\n", downloading);
+    if (downloading)
+    {
+        lto_download_stop();
+        return;
+    }
+
+    lto_download_percent_ = 0;
+    const char* msg = ltoDownloadStart();
+
+    if (msg)
+    {
+        lto_set_download_text(msg);
+        lto_pixmap_update();
+    }
+    else
+    {
+        lto_set_download_text("LTO download started");
+        lto_report(0);
+        downloading = true;
+
+        gtk_button_set_label(lto_download_button, "Stop Download");
+
+        lto_redraw();
+    }
+}
+
+static void
+lto_pixmap_clear()
+{
+    GtkWidget* w = GTK_WIDGET(LTO);
+    gdk_draw_rectangle(LTO_PIX, w->style->white_gc, TRUE,
+                       0, 0,
+                       w->allocation.width,
+                       w->allocation.height);
+}
+
+static gboolean
+event_configure_lto(GtkWidget* w, GdkEventConfigure* event)
+{
+    if (LTO_PIX)
+    {
+        g_object_unref(LTO_PIX);
+    }
+
+    //--------------------------------------------------------------------------
+    //          pixmap to make the strength bar meter easier to draw
+    //--------------------------------------------------------------------------
+    LTO_PIX = gdk_pixmap_new(w->window,
+                            w->allocation.width,
+                            w->allocation.height, -1);
+    // printf("LTO pixmap %d x %d\n", w->allocation.width, w->allocation.height);
+    lto_pixmap_clear();
+    return TRUE;
+}
+
+static gboolean
+event_expose_lto(GtkWidget* w, GdkEventExpose* event)
+{
+    notebook_expose("LT");
+
+    //  TODO:  figure out why we're being called so frequently:
+
+    lto_redraw();
+
+    GdkRectangle& a = event->area;
+    gdk_draw_drawable(w->window,
+                      w->style->fg_gc[GTK_WIDGET_STATE(w)],
+                      LTO_PIX, a.x, a.y, a.x, a.y, a.width, a.height);
+    return FALSE;
+}
+
+static GdkGC*
+alloc_color(GdkPixmap* pm, const char* color)
+{
+    GdkGC* result = 0;
+    if (!pm) return result;
+
+    GdkColormap* map = gdk_colormap_get_system();
+
+    GdkColor blue;
+    if (TRUE == gdk_color_parse(color, &blue))
+    {
+        if (TRUE == gdk_colormap_alloc_color(map, &blue, FALSE, TRUE))
+        {
+            GdkGCValues v;
+            v.foreground = blue;
+            result = gdk_gc_new_with_values(pm, &v, GDK_GC_FOREGROUND);
+            // printf("GC for %s 0x%x\n", color, result);
+        }
+        else printf("Can't alloc %s\n", color);
+    }
+    else printf("Can't parse %s\n", color);
+    return result;
+}
+
+static void
+page_lto_alloc_colors()
+{
+    if (!LTO_PIX) return;
+    if (!blue_gc) blue_gc = alloc_color(LTO_PIX, "Blue");
+    if (!grey_gc) grey_gc = alloc_color(LTO_PIX, "SlateGrey");
+}
+
+static void
+lto_draw_percent(bool age, int percent)
+{
+    page_lto_alloc_colors();
+    GdkGC* gc = GTK_WIDGET(LTO)->style->black_gc;
+
+    int line_width = 1;
+    int adj        = 4;
+    int x = 20;
+    int y = 35;
+    int h =  40;
+    int w = 400;
+
+    if (!age)
+    {
+        y += h * 2;             // draw the download progress
+    }
+
+    //----------------------------------------------
+    //      Draw the rectangle around the percent
+    //          (line width is implied in the GC)
+    //----------------------------------------------
+
+    gdk_draw_rectangle(LTO_PIX, gc, FALSE, x, y, w, h);
+
+    if (percent > 100) percent = 100;
+    if (percent <=  0) return;
+
+    //----------------------------------------------
+    //    Draw the percentage
+    //----------------------------------------------
+
+    x += adj;
+    y += adj;
+    h -= 2 * adj - line_width;
+    w -= 2 * adj - line_width;
+
+    int progress  = 50 + (w * percent);
+        progress /= 100;
+    gc = getGC(true);
+
+    gdk_draw_rectangle(LTO_PIX, gc, TRUE, x, y, progress, h);
+
+    //----------------------------------------------
+    //    Draw the percentage text
+    //
+    // % < 60:  Draw to the right of the bar.
+    // % > 60:  Draw to the left of the bar.
+    //----------------------------------------------
+
+
+    char buf[12];
+    sprintf(buf, "%d%%", percent);
+    pango_layout_set_text(LTO_text, buf, -1);
+
+    int w_text;
+    int h_text;
+    pango_layout_get_pixel_size(LTO_text, &w_text, &h_text);
+
+    y += (h-h_text)/2;
+    if (percent < 60)
+    {
+        x += 4 + progress;
+        // gc = getGC(true);            // blue on white looks OK.
+    }
+    else
+    {
+        x -= (4 - progress + w_text);
+        gc = getGC(false);              // light grey on blue looks OK.
+    }
+
+    // printf("lto_draw_percent(%s,%d) \"%s\" at (%d %d)\n",
+    //            (age) ? "age" : "download", percent, buf, x, y);
+    gdk_draw_layout(LTO_PIX, gc, x, y, LTO_text);
+}
+
+static void
+lto_pixmap_update()
+{
+    gtk_widget_queue_draw_area(GTK_WIDGET(LTO), 0, 0, PIXMAP_WIDTH, PIXMAP_WIDTH);
+}
+
+static void
+lto_redraw()
+{
+    if (!LTO_PIX)
+    {
+        // printf("lto_redraw()/%d: no LTO_PIX\n", __LINE__);
+        return;
+    }
+    lto_pixmap_clear();
+    lto_draw_percent(true, lto_age_percent);
+    if (downloading) lto_draw_download_progress();
+    lto_pixmap_update();
+}
+
+void
+page_LTO_init()
+{
+}
+
+void
+page_LTO_done()
+{
+    lto_redraw();
+}
+
+GtkWidget*
+page_LTO_create(GtkWidget* window)
+{
+    GtkWidget* label;
+    GtkWidget* button;
+    GtkWidget* w;
+    GtkWidget* vbox;
+    GtkWidget* table;
+
+    //--------------------------------------------------------------------------
+    //          table
+    //--------------------------------------------------------------------------
+    table = gtk_table_new(14, 2, TRUE);
+
+    //--------------------------------------------------------------------------
+    //          Page title label
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("LTO Status");
+    gtk_label_set_justify((GtkLabel*)label, GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 0, 1);
+    gtk_widget_show(label);
+    LTO_age_label = GTK_LABEL(label);
+
+    //--------------------------------------------------------------------------
+    //          label
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("Expired");
+    gtk_label_set_justify((GtkLabel*)label, GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 1, 2);
+    gtk_widget_show(label);
+    LTO_label = GTK_LABEL(label);
+    LTO_text = gtk_widget_create_pango_layout(label, "");
+
+    //--------------------------------------------------------------------------
+    //          window for the LTO bar
+    //--------------------------------------------------------------------------
+    w  = gtk_drawing_area_new();
+    LTO = GTK_DRAWING_AREA(w);
+    gtk_drawing_area_size(LTO, 476, 200);
+    gtk_signal_connect(GTK_OBJECT(w), "configure_event",
+                    G_CALLBACK(event_configure_lto), w);
+    gtk_signal_connect(GTK_OBJECT(w), "expose_event",
+                    G_CALLBACK(event_expose_lto), w);
+    gtk_widget_set_events(w, GDK_EXPOSURE_MASK);
+    gtk_table_attach_defaults(GTK_TABLE (table), w, 0, 2, 3, 8);
+    gtk_widget_show(w);
+
+    //--------------------------------------------------------------------------
+    //          Start Download button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("Start Download");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_start_download), button);
+    gtk_table_attach_defaults(GTK_TABLE (table), button, 0, 1, 13, 14);
+    gtk_widget_show(button);
+    lto_download_button = GTK_BUTTON(button);
+
+    //--------------------------------------------------------------------------
+    //          Factory Reset button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("Factory Reset");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_factory_reset), button);
+    gtk_table_attach_defaults(GTK_TABLE(table), button, 1, 2, 13, 14);
+    gtk_widget_show(button);
+
+    gtk_widget_show(table);
+
+    lto_report(0);
+    lto_file_lease(true);
+
+    return table;
+}
+
+//-------------------------------------------------------------------------------
+//
+//      Experimental feature to update the screen if the LTO file changes.
+//      Since the use of SIGIO inside GTK+ is unknown, I have a very
+//      risky signal forwarding chaining/cascading/forwarding algorithm.
+//      I can't find any references to this technique, so perhaps it won't
+//      work.
+//
+//      If omgui starts acting strangely, then perhaps use of SIGIO is the
+//      problem, and we can't forward it in this manner.  Fallbacks are:
+//
+//      0)  Drop this entire feature.  It is uncertain what to do with the
+//          output anyway.
+//      1)  Use a different signal.  Scan thru all the SIGUSRn until
+//          we find one that doesn't have a handler.
+//      2)  Fix this forwarding feature.
+//
+//-------------------------------------------------------------------------------
+
+#define OPT_LTO_LEASE
+#ifdef OPT_LTO_LEASE                    // {
+
+static int lto_file_fd = -1;
+static void lto_file_lease(bool getLease);
+static struct sigaction old_io;
+extern const char* cc_file;                     // See ltolib.cpp
+
+static bool
+sig_function(void* f)
+{
+    if ((void*)SIG_IGN == f) return false;
+    if ((void*)SIG_DFL == f) return false;
+    return true;
+}
+
+static void
+sig_lto_file_changed(int sigNum, struct siginfo* info, void* v)
+{
+    // Undocumented signal feature:
+    // ucontext_t* u = (ucontext_t*) v;
+
+    if ((info->si_fd == lto_file_fd) && (-1 != lto_file_fd))
+    {
+        printf("LTO file(%d) %s changed\n", lto_file_fd, cc_file);
+
+        // Free the lease right away, and then schedule an update
+        // of the screen info for the near future (somehow)...
+        lto_file_changed = true;
+        lto_file_lease(false);
+        return;
+    }
+
+    // Not our signal, forward it...
+    if (old_io.sa_flags & SA_SIGINFO)     // new signal style handler
+    {
+        if (sig_function((void*)old_io.sa_sigaction))
+        {
+            old_io.sa_sigaction(sigNum, info, v);
+        }
+        // else  not a function, so don't call
+    }
+    else                    // old style handler
+    {
+        if (sig_function((void*)old_io.sa_handler))
+        {
+            old_io.sa_handler(sigNum);
+        }
+    }
+}
+
+#define  OPT_LTO_LEASE
+#undef   OPT_LTO_LEASE
+
+static void
+lto_file_lease(bool getLease)
+{
+#ifdef  OPT_LTO_LEASE
+    const char* lto_file = cc_file;
+
+    printf("lto_file_lease(%d) %s have lease\n", getLease,
+                (-1 == lto_file_fd) ? "do not" : "DO");
+
+    if (getLease)
+    {
+        if (-1 != lto_file_fd) return;          // already have the lease
+        lto_file_fd = open(lto_file, O_RDONLY);
+
+        lto_file_changed = false;
+
+        fcntl(lto_file_fd, F_SETLEASE, F_RDLCK);
+
+        struct sigaction new_io;
+        new_io.sa_sigaction = sig_lto_file_changed;
+        new_io.sa_flags   = SA_SIGINFO;
+        sigemptyset(&new_io.sa_mask);
+        sigaction(SIGIO, &new_io, &old_io);
+    }
+    else                // free the lease
+    {
+        if (-1 == lto_file_fd) return;          // don't have the lease.
+        fcntl(lto_file_fd, F_SETLEASE, F_UNLCK);
+        close(lto_file_fd);
+        sigaction(SIGIO, &old_io, 0);
+        lto_file_fd = -1;
+    }
+#else
+    printf("lto_file_lease(%d)/%d  OPT_LEASE_LTO undefined\n", getLease);
+#endif
+}
+
+#else                                   // } {
+
+static void
+lto_file_lease(bool getLease)
+{
+    printf("NOT SUPPORTED: lto_file_lease(%d) \n", getLease);
+}
+
+#endif                                  // }
+
+
+
+void
+page_LTO_report(FILE* f)
+{
+    lto_report(f);
+}

Added: developers/olv/openmoko-agpsui2/src/page_SS.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_SS.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_SS.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,917 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "agps.h"
+#include "sv_bar.h"
+
+SV_bar bars[MAX_SVS];
+int SV_bar::nSS = 0;
+bool SV_bar::changed = false;
+int SV_bar::leastSamplesAveraged = 0;
+
+static GdkGC* blue_gc = 0;
+static GdkGC* grey_gc = 0;
+
+static GtkDrawingArea* SS;
+static GdkPixmap*      SS_PIX = 0;
+int dbm = 0;
+static PangoLayout* SS_text;
+GtkWidget* top4_button;
+
+//      KLUDGE for A3 or larger fonts only:
+// bool large_font  = true;
+// bool a3_hardware = true;
+#define large_font  1
+#define a3_hardware 1
+
+inline int
+format_ss(int dbHz)
+{
+    if (dbm) dbHz += DB_HZ_to_DBM;
+
+    if (large_font || a3_hardware)
+    {
+        if (dbHz < 0) dbHz = -dbHz;
+    }
+    return dbHz;
+}
+
+inline double
+format_ssf(double dbHz)
+{
+    if (dbm) return dbHz + DB_HZ_to_DBM;
+    return dbHz;
+}
+
+extern void notebook_expose(const char* pageName);
+
+static void SS_draw_bars();
+void page_SS_use_prn(int prn);
+void page_SS_have_prn(int prn, int ss, int el, int az);
+static double get_top_four_SVS();
+unsigned long msTime(void);
+
+//  Return a number between -100 and +100 along the X and Y axes.
+
+const double PI = 3.1415926535;
+
+int SV_bar::scale_radius(int r)
+{
+    r = 90 - r;
+    r *= LARGE_WINDOW_WIDTH/2;
+    r += 45;
+    return r/90;
+}
+
+void SV_bar::get_xy(int&x, int& y)
+{
+    float radius = (float) scale_radius(el);
+    float theta  = (float) -(az - 90);
+    float rad    = theta * PI/180.0;
+
+    float fx = radius * cos(rad);
+    float fy = radius * sin(rad);
+    x = (int) (fx + 0.5);
+    y = (int) (fy + 0.5);
+
+    //printf("get_xy:  r %f,  theta %f   rad %f   fx %f   fy %f\n",
+    //                 radius,theta,     rad,     fx,     fy);
+}
+
+GtkLabel* ss_label;
+
+void SS_reset_max_min()
+{
+    unsigned long ms = msTime();
+    for (int b = 0; b < SV_bar::nSS; ++b)
+    {
+        SV_bar& sv = bars[b];
+        if (!sv.use) continue;
+
+        sv.ss_max_time = ms;
+        sv.ss_min_time = ms;
+        sv.ss_max      = sv.ss;
+        sv.ss_min      = sv.ss;
+    }
+}
+
+void SS_reset_average()
+{
+    for (int b = 0; b < SV_bar::nSS; ++b)
+    {
+        SV_bar&  sv = bars[b];
+        sv.nAvg     = 0;
+        sv.sumAvg   = 0;
+        sv.indexAvg = 0;
+    }
+}
+
+static void
+on_clicked_reset_max_min(GtkWidget* w, gpointer d)
+{
+    SS_reset_max_min();
+    SS_draw_bars();
+}
+
+static void
+reset_top4()
+{
+    gtk_button_set_label(GTK_BUTTON(top4_button), "Top 4 SV");
+}
+
+static void
+on_clicked_top4(GtkWidget* w, gpointer data)
+{
+    double top4     = format_ssf(get_top_four_SVS());
+    int    nSamples = SV_bar::leastSamplesAveraged;
+    if (nSamples)
+    {
+        char buf[64];
+        sprintf(buf,"Top 4 %.1f (%d)", top4, nSamples);
+        gtk_button_set_label(GTK_BUTTON(w), buf);
+    }
+    else
+    {
+        reset_top4();
+    }
+}
+
+static void
+on_clicked_reset_average(GtkWidget* w, gpointer d)
+{
+    SS_reset_average();
+    reset_top4();
+    SS_draw_bars();
+}
+
+static void
+on_ss_units_change()
+{
+    const char* units = "Signal Strength (dB.Hz)";
+    if (dbm) units = "Signal Strength (dBm)";
+    gtk_label_set_text(ss_label, units);
+}
+
+static void
+on_clicked_dbm(GtkWidget* widget, gpointer data)
+{
+    dbm = 1 - dbm;
+    gtk_button_set_label(GTK_BUTTON(data), (dbm) ? "dBm" : "C/N0");
+    on_ss_units_change();
+    reset_top4();
+    SS_draw_bars();
+}
+
+static void
+SS_clear()
+{
+    GtkWidget* w = GTK_WIDGET(SS);
+    gdk_draw_rectangle(SS_PIX, w->style->white_gc, TRUE,
+                       0, 0,
+                       w->allocation.width,
+                       w->allocation.height);
+}
+
+static gboolean
+configure_SS_event(GtkWidget* w, GdkEventConfigure* event)
+{
+    if (SS_PIX)
+    {
+        g_object_unref(SS_PIX);
+    }
+
+    //--------------------------------------------------------------------------
+    //          pixmap to make the strength bar meter easier to draw
+    //--------------------------------------------------------------------------
+    SS_PIX = gdk_pixmap_new(w->window,
+                            w->allocation.width,
+                            w->allocation.height, -1);
+    SS_clear();
+    return TRUE;
+}
+
+static gboolean
+expose_SS_event(GtkWidget* w, GdkEventExpose* event)
+{
+    notebook_expose("SS");
+    GdkRectangle& a = event->area;
+    gdk_draw_drawable(w->window,
+                      w->style->fg_gc[GTK_WIDGET_STATE(w)],
+                      SS_PIX, a.x, a.y, a.x, a.y, a.width, a.height);
+    return FALSE;
+}
+
+void
+page_SS_done()
+{
+    if (!SV_bar::changed) return;
+    SV_bar::changed = false;
+    SS_draw_bars();
+}
+
+static int
+SS_width(int maxWidth)
+{
+    int n = SV_bar::nSS;
+    if (SV_bar::nSS < 1)
+    {
+        n = 1;
+    }
+    int seps = n+1;
+    return (maxWidth - seps * SEP_WIDTH) / n;
+}
+
+static GdkGC* 
+getGC(bool used)
+{
+    GdkGC* gc = grey_gc;
+    if (used)
+    {
+        gc = blue_gc;                   // used SV is colored blue
+    }
+    if (!gc)
+    {
+        gc = GTK_WIDGET(SS)->style->black_gc;
+    }
+    return gc;
+}
+
+static void
+SS_draw_line(int x0, int y0, int x1, int y1)
+{
+    printf("AZ_draw_line(%d,%d,%d,%d)\n", x0, y0, x1, y1);
+    gdk_draw_line(SS_PIX, getGC(false), x0, y0, x1, y1);
+}
+
+//------------------------------------------------------------------------------------
+//
+//      dbHz_to_pixels()
+//
+//      dBm     C/N0    Pixels  Use
+//      -120      53    BAR_HEIGHT        Maximum
+//      -133      40    <scaled properly> Typical
+//      -163      10    0                 Minimum
+//
+//------------------------------------------------------------------------------------
+
+int dbHz_to_pixels(int dbHz)
+{
+    if (dbHz >= 53) return BAR_HEIGHT;
+    if (dbHz <= 10) return 0;
+    dbHz -= 10;
+    dbHz *= BAR_HEIGHT;
+    dbHz += 21;                 // Rounding.
+    dbHz /= 43;
+    return dbHz;
+}
+
+GdkGC*
+alloc_color(GdkPixmap* pm, const char* color)
+{
+    GdkGC* result = 0;
+    if (!pm) return result;
+
+    GdkColormap* map = gdk_colormap_get_system();
+
+    GdkColor blue;
+    if (TRUE == gdk_color_parse(color, &blue))
+    {
+        if (TRUE == gdk_colormap_alloc_color(map, &blue, FALSE, TRUE))
+        {
+            GdkGCValues v;
+            v.foreground = blue;
+            result = gdk_gc_new_with_values(pm, &v, GDK_GC_FOREGROUND);
+            // printf("GC for %s 0x%x\n", color, result);
+        }
+        else printf("Can't alloc %s\n", color);
+    }
+    else printf("Can't parse %s\n", color);
+    return result;
+}
+
+void
+page_SS_alloc_colors()
+{
+    if (!SS_PIX) return;
+    if (!blue_gc) blue_gc = alloc_color(SS_PIX, "Blue");
+    if (!grey_gc) grey_gc = alloc_color(SS_PIX, "SlateGrey");
+}
+
+//-------------------------------------------------------------------------------------
+//
+//              SS_draw_el()
+//
+//  Draw a black filled arc showing the elevation at the bottom of the bar.
+//  (x,y) should be the lower-left corner of the signal strength bar.
+//
+//  Max width is 40.
+//
+//-------------------------------------------------------------------------------------
+
+static void
+SS_draw_el(SV_bar& sv, int x, int y, int width)
+{
+    if (!sv.use) return;
+
+    int arcN = sv.el * DEGREE_64;
+    if (sv.el < MIN_ELEVATION) arcN = MIN_ELEVATION * DEGREE_64;
+
+    const int max_width = 50;
+    if (width > max_width)
+    {
+        x += (width - max_width)/2;
+        width = max_width;
+    }
+
+    gdk_draw_arc(SS_PIX, GTK_WIDGET(SS)->style->black_gc, TRUE,
+                x-width,  y-width,
+                  width*2,  width*2,
+                0, arcN);
+}
+
+enum
+{
+    SS_SMALL = 1,
+    SS_TEXT  = 2
+};
+
+static void
+SS_draw_ss(int ss, int y, int w, int flags)
+{
+    page_SS_alloc_colors();
+    GdkGC* gc = getGC(false);
+
+    int font_height = 16;               // TODO: see how to get this.
+    int barHeightPixels = dbHz_to_pixels(ss);
+
+    int base_y = y + BAR_HEIGHT + 2 * font_height;
+
+    int h = 3;
+    int r_y    = base_y - barHeightPixels - 1;
+
+    //----------------------------------------------
+    //          Draw the signal strength rule
+    //----------------------------------------------
+    if (flags & SS_SMALL)
+    {
+        ++r_y;
+        h = 1;
+    }
+    gdk_draw_rectangle(SS_PIX, gc, TRUE, 0, r_y, w, h);
+
+    //----------------------------------------------
+    //          Draw the signal strength text
+    //----------------------------------------------
+    if (flags & SS_TEXT)
+    {
+        char dbmString[8];
+        sprintf(dbmString, "%d", format_ss(ss));
+        pango_layout_set_text(SS_text, dbmString, -1);
+        if (flags & SS_SMALL) w += SEP_WIDTH;
+        gdk_draw_layout(SS_PIX, getGC(false),
+                        w + SEP_WIDTH, r_y - FONT_HEIGHT/2, SS_text);
+    }
+}
+
+static void
+SS_draw_bar(SV_bar& sv, int x, int y, int width, bool barOnly)
+{
+    int font_height = 16;               // TODO: see how to get this.
+
+    int barHeightPixels = dbHz_to_pixels(sv.ss);
+
+    page_SS_alloc_colors();
+
+    //----------------------------------------------
+    //          Draw the signal strength bar
+    //----------------------------------------------
+
+    int base_y = y + BAR_HEIGHT + 2*font_height;
+    int r_y = base_y - barHeightPixels;
+    int r_height = barHeightPixels;
+
+    GdkGC* gc = getGC(sv.use);
+
+    if (barOnly)
+        gdk_draw_rectangle(SS_PIX, gc, TRUE, x, r_y, width, r_height);
+
+    //----------------------------------------------
+    //          Draw the elevation arc
+    //----------------------------------------------
+
+    SS_draw_el(sv, x, base_y, width);
+
+    //----------------------------------------------
+    //          Draw the minimum level (if it exists)
+    //          Draw the maximim level (if it exists)
+    //----------------------------------------------
+    if (sv.use && barOnly)
+    {
+        GdkGC* black_gc = GTK_WIDGET(SS)->style->black_gc;
+        if (sv.ss_min_time)
+        {
+            barHeightPixels = dbHz_to_pixels(sv.ss_min);
+            r_y = base_y - barHeightPixels;
+            gdk_draw_rectangle(SS_PIX, black_gc, TRUE,
+                                x + width/4, r_y - 1, width/2, 3);
+        }
+        if (sv.ss_max_time)
+        {
+            barHeightPixels = dbHz_to_pixels(sv.ss_max);
+            r_y = base_y - barHeightPixels;
+            gdk_draw_rectangle(SS_PIX, black_gc, TRUE,
+                                x, r_y - 1, width, 3);
+        }
+    }
+
+    //----------------------------------------------
+    //          Draw the average SS text
+    //----------------------------------------------
+
+    if (!barOnly)
+    {
+        int yy = y;
+        int xx = x + 3;
+
+        //----------------------------------------------
+        //          Draw the signal strength average
+        //          Draw the signal strength text
+        //----------------------------------------------
+
+        if (sv.use)
+        {
+            char dbmString[8];
+
+            int i_dbm = sv.avg_ss();
+            if (!i_dbm)
+            {
+                sprintf(dbmString, "-");
+                xx += 4;
+            }
+            else
+            {
+                sprintf(dbmString, "%d", format_ss(sv.avg_ss()));
+            }
+
+            pango_layout_set_text(SS_text, dbmString, -1);
+            gdk_draw_layout(SS_PIX, gc, xx, yy, SS_text);
+
+            sprintf(dbmString, "%d", format_ss(sv.ss));
+            pango_layout_set_text(SS_text, dbmString, -1);
+            gdk_draw_layout(SS_PIX, gc, x+3, y + font_height + 4, SS_text);
+        }
+
+        //----------------------------------------------
+        //          Draw the PRN text
+        //----------------------------------------------
+
+        char prn[4];
+        sprintf(prn, "%d", sv.prn);
+        pango_layout_set_text(SS_text, prn, -1);
+        xx = (sv.prn > 9) ?
+                    x + width/2 - 12                   // TODO: center this.
+                :   x + width/2 -  5;                  // TODO: center this.
+        yy = y + BAR_HEIGHT + 2*font_height;
+        gdk_draw_layout(SS_PIX, gc, xx, yy, SS_text);
+        // printf("PRN \"%s\" at {x %d  y %d}\n", prn, xx, yy);
+    }
+}
+
+static void
+SS_draw_bars()
+{
+    if (!SS_PIX) return;
+    SS_clear();
+
+    //  Leave some space to the right for the markers, etc.
+    int w = SS_width(PIXMAP_WIDTH - 60);
+    int indicator_w = SV_bar::nSS * (SEP_WIDTH + w) + SEP_WIDTH;
+    int y = 10;
+
+    //----------------------------------------------
+    //          Draw the small SS horizontal lines
+    //----------------------------------------------
+    if (dbm)
+    {
+        SS_draw_ss(48, y, indicator_w, SS_SMALL);        // -125 dBm MAX
+        SS_draw_ss(43, y, indicator_w, SS_TEXT);         // -130 dBm
+        SS_draw_ss(38, y, indicator_w, SS_SMALL);
+        SS_draw_ss(33, y, indicator_w, SS_TEXT);         // -140 dBm
+        SS_draw_ss(28, y, indicator_w, SS_SMALL);
+        SS_draw_ss(23, y, indicator_w, SS_TEXT);         // -150 dBm
+        SS_draw_ss(18, y, indicator_w, SS_SMALL);
+        SS_draw_ss(13, y, indicator_w, SS_TEXT);         // -160 dBm MIN
+    }
+    else
+    {
+        SS_draw_ss(50, y, indicator_w, SS_TEXT);        // 50 dBm MAX
+        SS_draw_ss(45, y, indicator_w, SS_SMALL);
+        SS_draw_ss(40, y, indicator_w, SS_TEXT);
+        SS_draw_ss(35, y, indicator_w, SS_SMALL);
+        SS_draw_ss(30, y, indicator_w, SS_TEXT);
+        SS_draw_ss(25, y, indicator_w, SS_SMALL);
+        SS_draw_ss(20, y, indicator_w, SS_TEXT);
+        SS_draw_ss(15, y, indicator_w, SS_SMALL);
+        SS_draw_ss(13, y, indicator_w, SS_SMALL | SS_TEXT);  // -160 dBm MIN
+    }
+
+    int x = SEP_WIDTH;
+    if (SV_bar::nSS)
+    {
+        for (int b = 0; b < SV_bar::nSS; ++b)
+        {
+            SS_draw_bar(bars[b], x, y, w, true );
+            x += SEP_WIDTH + w;
+        }
+    }
+
+    x = SEP_WIDTH;
+    if (SV_bar::nSS)
+    {
+        for (int b = 0; b < SV_bar::nSS; ++b)
+        {
+            SS_draw_bar(bars[b], x, y, w, false);
+            x += SEP_WIDTH + w;
+        }
+    }
+
+    //----------------------------------------------
+    //          Draw the "avg" SS text
+    //----------------------------------------------
+    pango_layout_set_text(SS_text, "avg", -1);
+    gdk_draw_layout(SS_PIX, GTK_WIDGET(SS)->style->black_gc, indicator_w, y, SS_text);
+
+    // gtk_widget_queue_draw_area(GTK_WIDGET(SS), 0, 0, 400, 500);
+    gtk_widget_queue_draw_area(GTK_WIDGET(SS), 0, 0, PIXMAP_WIDTH, PIXMAP_WIDTH);
+}
+
+//------------------------------------------------------------------------------
+//
+//         get_top_SV
+//
+//   Return the signal strength of the strongest SV
+//   that is not in MASK
+//
+//------------------------------------------------------------------------------
+
+#define BIT(b)  (1 << (b))
+
+static int get_top_SV(int& mask)
+{
+    int our_mask = 0;
+    int max = 0;
+    for (int b = 0; b < SV_bar::nSS; ++b)
+    {
+        int m = BIT(b);
+        if (m & mask) continue;
+        SV_bar& sv = bars[b];
+        int avg = sv.avg_ss();
+        if (avg > max)
+        {
+            our_mask = m;
+            max = avg;
+            int n = sv.nAvg;
+            if (n > N_AVG) n = N_AVG;
+            if (n < SV_bar::leastSamplesAveraged)
+            {
+                SV_bar::leastSamplesAveraged = n;
+            }
+        }
+    }
+    mask |= our_mask;
+    printf("top 4:  0x%x %d\n", our_mask, max);
+    return max;
+}
+
+static double get_top_four_SVS()
+{
+    int mask = 0;
+    double sum = 0;
+    int total = 0;
+    int avg;
+    SV_bar::leastSamplesAveraged = N_AVG;
+
+    avg  = get_top_SV(mask);
+    sum += avg;
+
+    if (!avg)
+    {
+        SV_bar::leastSamplesAveraged = 0;
+        return 0.0;
+    }
+    avg = get_top_SV(mask); sum += avg; if (!avg) return sum;
+    avg = get_top_SV(mask); sum += avg; if (!avg) return sum/2.0;
+    avg = get_top_SV(mask); sum += avg; if (!avg) return sum/3.0;
+
+    return sum / 4.0;
+}
+
+static int
+update_prn(int prn, int ss, int el, int az)
+{
+    for (int b = 0; b < SV_bar::nSS; ++b)
+    {
+        if (prn == bars[b].prn)
+        {
+            SV_bar& sv = bars[b];
+            if ((sv.el == el) && (sv.az == az) && (sv.ss == ss))
+            {
+                return 0;
+            }
+            if ((sv.el != el) || (sv.az != az))
+            {
+                // printf("Change PRN %d  el %d-->%d   az %d-->%d\n", 
+                //             sv.prn, sv.el, el, sv.az, az);
+                sv.el = el;
+                sv.az = az;
+            }
+            sv.ss         = ss;
+            sv.lastUpdate = msTime();
+            if ((ss > sv.ss_max)) //  || ((sv.lastUpdate - sv.ss_max_time) > 1000*60))
+            {
+                sv.ss_max_time = sv.lastUpdate;
+                sv.ss_max = ss;
+            }
+
+            //  Either we have a new minimum signal strength; OR
+            //  We time-out the min signal
+            if ((ss < sv.ss_min)) //  || ((sv.lastUpdate - sv.ss_min_time) > 1000*60))
+            {
+                sv.ss_min_time = sv.lastUpdate;
+                sv.ss_min = ss;
+            }
+            return 1;
+        }
+    }
+    return -1;
+}
+
+static int
+findUnusedSV()
+{
+    unsigned long oldest_ms = msTime();
+    int oldest = -1;
+
+    for (int b = 0; b < SV_bar::nSS; ++b)
+    {
+        if (bars[b].use) continue;
+        if (bars[b].lastUpdate < oldest_ms)
+        {
+            oldest_ms = bars[b].lastUpdate;
+            oldest    = b;
+        }
+    }
+    return oldest;
+}
+
+unsigned long msTime(void);
+
+static void
+use_prn(int prn)
+{
+    for (int b = 0; b < SV_bar::nSS; ++b)
+    {
+        SV_bar& sv = bars[b];
+        if (prn == sv.prn)
+        {
+            if (!sv.use)
+            {
+                SV_bar::changed  = true;
+                sv.use = true;
+            }
+            sv.add_ss();
+            sv.lastUpdate = msTime();
+            return;
+        }
+    }
+}
+
+void
+page_SS_unuse_prns()
+{
+    for (int b = 0; b < SV_bar::nSS; ++b)
+    {
+        bars[b].use = false;
+    }
+}
+
+void
+page_SS_use_prn(int prn)
+{
+    // printf("page_SS_use_prn(%d)\n", prn);
+    if (prn <  1) return;
+    if (prn > 32) return;               // Haven't launched PRN 33 yet.
+    use_prn(prn);
+}
+
+void
+page_SS_have_prn(int prn, int ss, int el, int az)
+{
+    // printf("page_SS_have_prn(%d %d   %d:%d) %d\n", prn, ss, el, az, SV_bar::nSS);
+    if (prn <  1) return;
+    if (prn > 32) return;               // Haven't launched PRN 33 yet.
+
+    switch (update_prn(prn, ss, el, az))
+    {
+    case 0:
+        return;
+    case 1:
+        SV_bar::changed = true;
+        return;
+    default:
+        break;
+    }
+
+    int nextSV = SV_bar::nSS;
+    if (SV_bar::nSS < MAX_SVS)
+    {
+        // TODO:  remove unused SVs.
+        ++SV_bar::nSS;
+    }
+    else
+    {
+        nextSV = findUnusedSV();
+        if (nextSV < 0) return;
+    }
+
+    // printf("add %d = {%d %d}\n", nextSV, prn, ss);
+    SV_bar& sv = bars[nextSV];
+    sv.init();
+    sv.prn = prn;
+    sv.ss  = ss;
+    sv.el  = el;
+    sv.az  = az;
+    sv.lastUpdate = msTime();
+
+    SV_bar::changed = true;
+}
+
+void
+page_SS_init()
+{
+    memset(bars, 0, sizeof(bars));
+    SV_bar::nSS = 0;
+}
+
+GtkWidget*
+page_SS_create(GtkWidget* window)
+{
+    GtkWidget* label;
+    GtkWidget* button;
+    GtkWidget* w;
+    GtkWidget* vbox;
+    GtkWidget* table;
+
+    //--------------------------------------------------------------------------
+    //          table
+    //--------------------------------------------------------------------------
+    table = gtk_table_new(14, 2, TRUE);
+
+    //--------------------------------------------------------------------------
+    //          label
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("Signal Strength (db.Hz)");
+    gtk_label_set_justify((GtkLabel*)label, GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 0, 1);
+    gtk_widget_show(label);
+    ss_label = GTK_LABEL(label);
+
+    SS_text = gtk_widget_create_pango_layout(label, "");
+
+    //--------------------------------------------------------------------------
+    //          window for the strength bar meters
+    //--------------------------------------------------------------------------
+    w  = gtk_drawing_area_new();
+    SS = GTK_DRAWING_AREA(w);
+    gtk_drawing_area_size(SS, 500, 500);
+
+    gtk_signal_connect(GTK_OBJECT(w), "configure_event",
+                    G_CALLBACK(configure_SS_event), w);
+
+    gtk_signal_connect(GTK_OBJECT(w), "expose_event",
+                    G_CALLBACK(expose_SS_event), w);
+
+    gtk_widget_set_events(w, GDK_EXPOSURE_MASK);
+    gtk_table_attach_defaults(GTK_TABLE (table), w, 0, 2, 1, 12);
+    gtk_widget_show(w);
+
+#if 0
+    //--------------------------------------------------------------------------
+    //          Reset Average button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("Reset Max");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_reset_max_min), button);
+    gtk_table_attach_defaults(GTK_TABLE (table), button, 0, 1, 12, 13);
+    gtk_widget_show(button);
+#else
+    //--------------------------------------------------------------------------
+    //          Reset max/min button
+    //--------------------------------------------------------------------------
+    GtkWidget* box = gtk_hbox_new (FALSE, 2);
+
+    button = gtk_button_new_with_label("Reset max");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_reset_max_min), button);
+    gtk_widget_show(button);
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 1);
+
+    //--------------------------------------------------------------------------
+    //          Reset average button
+    //--------------------------------------------------------------------------
+
+    button = gtk_button_new_with_label("Reset avg");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_reset_average), button);
+    gtk_widget_show(button);
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 1);
+
+    gtk_widget_show(box);
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 0, 1, 12, 13);
+#endif
+
+    //--------------------------------------------------------------------------
+    //          dBm or C/N0 button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("dBm");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_dbm), button);
+    gtk_table_attach_defaults(GTK_TABLE (table), button, 0, 1, 13, 14);
+    gtk_widget_show(button);
+
+    //--------------------------------------------------------------------------
+    //          Top 4 SV Average button
+    //--------------------------------------------------------------------------
+    top4_button = gtk_button_new_with_label("");
+    g_signal_connect(G_OBJECT(top4_button), "clicked",
+                     G_CALLBACK(on_clicked_top4), top4_button);
+    gtk_table_attach_defaults(GTK_TABLE(table), top4_button, 1, 2, 13, 14);
+    reset_top4();
+    gtk_widget_show(top4_button);
+
+    gtk_widget_show(table);
+    return table;
+}
+
+static void
+SS_report_bar(SV_bar& sv, FILE* f)
+{
+    fprintf(f, " %2d", sv.prn);
+    fprintf(f, "     %2d", sv.ss);
+
+    int i_dbm = sv.avg_ss();
+    if (i_dbm) fprintf(f, "   %2d", i_dbm);
+    else       fprintf(f, "     ");
+
+    if (sv.ss_min_time) fprintf(f, "   %2d", sv.ss_min);
+    else                fprintf(f, "     ");
+
+    if (sv.ss_max_time) fprintf(f, "   %2d", sv.ss_max);
+    else                fprintf(f, "     ");
+
+    fprintf(f, "         %2d", sv.el);
+    fprintf(f, "      %3d",    sv.az);
+
+    if (sv.use) fprintf(f, "  y\n");
+    else        fprintf(f, "  UNUSED\n");
+}
+
+void
+page_SS_report(FILE* f)
+{
+    fprintf(f, "PRN  dB.Hz  AVG  min  MAX  Elevation  Azimuth  Used\n");
+    for (int b = 0; b < SV_bar::nSS; ++b)
+    {
+        SS_report_bar(bars[b], f);
+    }
+    fprintf(f, "\n");
+
+    double top4     = format_ssf(get_top_four_SVS());
+    int    nSamples = SV_bar::leastSamplesAveraged;
+    if (nSamples)
+    {
+        fprintf(f, "Top 4 SVs %.1f (%d)\n", top4, nSamples);
+    }
+}

Added: developers/olv/openmoko-agpsui2/src/page_add.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_add.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_add.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <stdlib.h>
+
+//      Dummy page to show how to add another page easily.
+
+GtkWidget* add_msg;
+
+static void 
+page_ADD_init() 
+{
+}
+
+static void 
+on_clicked_connect(GtkWidget *widget, gpointer data) 
+{
+    g_print("User has clicked button connect\n");
+}
+
+static void 
+on_clicked_dial(GtkWidget *widget, gpointer data) 
+{
+    g_print("User has clicked button dial\n");
+}
+
+static void 
+on_clicked_acp(GtkWidget *widget, gpointer data) 
+{
+    g_print("User has clicked button accept\n");
+}
+
+static void
+on_clicked_hangup(GtkWidget *widget, gpointer data)
+{
+    g_print("User has clicked button hangup\n");
+}
+
+GtkWidget*
+page_ADD_create(GtkWidget* window)
+{
+    GtkWidget* table = gtk_table_new(14,10,TRUE);
+    GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+    gtk_table_attach_defaults (GTK_TABLE (table), scrolled_window, 0, 10, 0, 11);
+
+    GtkWidget* hb1 = gtk_frame_new ("Test Message");
+    add_msg = gtk_label_new("");
+    gtk_label_set_justify((GtkLabel*)add_msg, GTK_JUSTIFY_LEFT);
+    gtk_container_add (GTK_CONTAINER (hb1), add_msg);
+    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
+                    hb1);
+
+    GtkWidget* frame_table = gtk_table_new (2, 2, TRUE);
+    GtkWidget* start_btn = gtk_button_new_with_label ("Connect");
+    g_signal_connect(G_OBJECT(start_btn),
+                     "clicked",G_CALLBACK (on_clicked_connect), NULL);
+    gtk_table_attach_defaults (GTK_TABLE (frame_table), start_btn, 0, 1, 0, 1);
+    
+    GtkWidget* dial_btn = gtk_button_new_with_label ("Dial 112");
+    g_signal_connect(G_OBJECT(dial_btn),
+                     "clicked",G_CALLBACK (on_clicked_dial), NULL);
+    gtk_table_attach_defaults (GTK_TABLE (frame_table), dial_btn, 1, 2, 0, 1);
+
+    GtkWidget* acp_btn = gtk_button_new_with_label ("Accept");
+    g_signal_connect(G_OBJECT(acp_btn), "clicked", G_CALLBACK(on_clicked_acp), NULL);
+    gtk_table_attach_defaults (GTK_TABLE (frame_table), acp_btn, 0, 1, 1, 2);
+    GtkWidget* hang_btn = gtk_button_new_with_label ("Hang up");
+    g_signal_connect(G_OBJECT(hang_btn),
+                     "clicked", G_CALLBACK(on_clicked_hangup), NULL);
+    gtk_table_attach_defaults (GTK_TABLE (frame_table), hang_btn, 1, 2, 1, 2);
+    gtk_table_attach_defaults(GTK_TABLE (table), frame_table, 0, 10, 11, 14);
+
+    gtk_widget_show(scrolled_window);
+    gtk_widget_show(hb1);
+    gtk_widget_show(add_msg);
+    gtk_widget_show(frame_table);
+    gtk_widget_show(start_btn);
+    gtk_widget_show(dial_btn);
+    gtk_widget_show(acp_btn);
+    gtk_widget_show(hang_btn);
+    gtk_widget_show(table);
+
+    printf("%s/%d\n", __FILE__, __LINE__);
+    return table;
+}
+
+void
+page_ADD_report(FILE* f)
+{
+    fprintf(f, "Say something about %s/%d\n", __FILE__, __LINE__);
+}

Added: developers/olv/openmoko-agpsui2/src/page_log.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_log.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_log.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,135 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#define MAX_LINES 40
+
+enum {
+	COLUMN_TIME,
+	COLUMN_NMEA,
+	N_COLUMNS
+};
+
+static GtkListStore *store;
+static int num_lines;
+static gboolean locked;
+
+unsigned long int runtime_ms();
+
+void page_log_append(const char *nmea)
+{
+	GtkTreeIter iter;
+
+	if (!store || locked)
+		return;
+
+	if (num_lines >= MAX_LINES)
+	{
+		if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
+		{
+			if (gtk_list_store_remove(store, &iter))
+				num_lines--;
+		}
+	}
+
+	if (num_lines < MAX_LINES)
+	{
+		gtk_list_store_append(store, &iter);
+		gtk_list_store_set(store, &iter, COLUMN_TIME, runtime_ms(), COLUMN_NMEA, nmea, -1);
+		num_lines++;
+	}
+}
+
+static GtkTreeModel *create_model(void)
+{
+	store = gtk_list_store_new(N_COLUMNS, G_TYPE_INT, G_TYPE_STRING);
+
+	return GTK_TREE_MODEL(store);
+}
+
+#ifdef SELF_PRODUCING
+static gboolean add_nmea(gpointer data)
+{
+	gchar buf[256];
+
+	g_snprintf(buf, sizeof(buf), "%d", num_lines);
+
+	page_log_append(buf);
+
+	return TRUE;
+}
+#endif
+
+static void on_lock_clicked(GtkWidget *w, gpointer data)
+{
+	locked = !locked;
+
+	gtk_button_set_label(GTK_BUTTON(w), (locked) ? "Unlock" : "Lock");
+}
+
+GtkWidget*
+page_log_create(GtkWidget* window)
+{
+	GtkWidget *vbox, *button, *scroll, *view;
+	GtkTreeModel *model;
+	GtkTreeViewColumn *column;
+	GtkTreeSelection *selection;
+	GtkCellRenderer *cell;
+
+	model = create_model();
+	view = gtk_tree_view_new_with_model(model);
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+	gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
+
+	cell = gtk_cell_renderer_text_new();
+
+	column = gtk_tree_view_column_new_with_attributes("Time", cell, "text", COLUMN_TIME, NULL);
+	gtk_tree_view_column_set_min_width(GTK_TREE_VIEW_COLUMN(column), 80);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
+
+	column = gtk_tree_view_column_new_with_attributes("NMEA", cell, "text", COLUMN_NMEA, NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
+
+	scroll = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_container_add(GTK_CONTAINER(scroll), view);
+
+	button = gtk_button_new_with_label("Lock");
+	g_signal_connect(button, "clicked", G_CALLBACK(on_lock_clicked), NULL);
+
+	vbox = gtk_vbox_new(FALSE, 0);
+	gtk_box_pack_start_defaults(GTK_BOX(vbox), scroll);
+	gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
+
+	gtk_widget_show_all(vbox);
+
+#ifdef SELF_PRODUCING
+	g_timeout_add(500, add_nmea, NULL);
+#endif
+
+	return vbox;
+}

Added: developers/olv/openmoko-agpsui2/src/page_main.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_main.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_main.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,440 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include "agps.h"
+
+extern void notebook_expose(const char* pageName);
+
+#ifndef AGPS_H_
+#include "agps.h"
+#endif 
+
+extern void page_stress_on(void);
+extern void page_stress_msg(const char* msg);
+
+extern void create_range_controls(GtkWidget* window, GtkWidget* vbox, bool test);
+extern const char* gllin_detect(void);
+extern const char* gllin_start(void);
+extern const char* gllin_stop(void);
+extern void gllin_reset(char c);
+extern void agps_cb_start(GtkWidget* label);
+extern void agps_cb_stop(void);
+extern void agps_stop(void);
+extern void clearStats(void);
+extern void page_pm_batch_start();
+
+extern GtkLabel* agpsLabel;
+extern void NMEA_MSG(const char* msg);
+
+static bool gllinRunning = false;
+bool doing_ptf = false;
+extern bool doing_batch;
+extern bool doing_stress;
+
+//-------------------------------------------------------------------------------------
+//
+//              OMGUI versions
+//
+//-------------------------------------------------------------------------------------
+
+#define OMGUI_MAJOR     0
+#define OMGUI_MINOR     20
+
+const char*
+page_main_omgui_version(void)
+{
+    static char buf[64];
+    sprintf(buf, "OpenMoko GPS UI v%d.%02d", OMGUI_MAJOR, OMGUI_MINOR);
+    return buf;
+}
+
+//-------------------------------------------------------------------------------------
+//
+//              millisecond timer()
+//
+//-------------------------------------------------------------------------------------
+
+unsigned long msTime(void)
+{
+    struct timespec t;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    unsigned long ms = t.tv_nsec/1000000;
+    ms += t.tv_sec * 1000;
+    return ms;
+}
+
+static unsigned long msStart;
+
+void runtime_init()
+{
+    msStart = msTime();
+}
+
+unsigned long int runtime_ms()
+{
+    return msTime() - msStart;
+}
+
+unsigned long int runtime()
+{
+    return (runtime_ms() + 499) / 1000;
+}
+
+char testStartTime[16];
+
+GtkWidget* startWidget = 0;
+GtkWidget* ptfWidget   = 0;
+
+char test_name[64];
+extern void page_stress_set_report_name(void);
+
+const char* page_main_test_name()
+{
+    if (test_name[0]) return test_name;
+    return 0;
+}
+
+static char*
+page_main_format_date(char* date, bool startTime)
+{
+    time_t aclock;
+    time(&aclock);                      /* Get time in seconds */
+    struct tm* t = localtime(&aclock);  /* Convert time to struct tm form */
+
+    sprintf(date, "%02d:%02d %04d/%02d/%02d",
+                    t->tm_hour, t->tm_min,
+                    t->tm_year + 1900, t->tm_mon + 1, t->tm_mday);
+
+    if (startTime)
+    {
+        sprintf(testStartTime, "%02d:%02d", t->tm_hour, t->tm_min);
+        sprintf(test_name,     "%02d%02d",  t->tm_hour, t->tm_min);
+        page_stress_set_report_name();
+    }
+}
+
+static char previousTestTime[32];
+
+const char* nmea_epoch();
+
+void
+page_main_stop(const char* err)
+{
+    const char* msg = "";
+    if (err)
+    {
+        msg = "error: ";
+        NMEA_MSG(err);
+    }
+    else
+    {
+        err = "successfully";
+    }
+    agps_cb_stop();
+
+    gtk_button_set_label(GTK_BUTTON(startWidget), "Power on");
+    gllinRunning = false;
+    gtk_widget_set_sensitive(ptfWidget, true);
+
+    char date[32];
+    page_main_format_date(date, false);
+
+    char buf[2048];
+    sprintf(buf, "Stopped gllin %s%s\n"
+                 "at %s\n"
+                 "run time %d seconds\n"
+                 "Previous test data\n%s\n",
+                     msg, err, date, runtime(),
+                     nmea_epoch());
+    NMEA_MSG(buf);
+}
+
+//------------------------------------------------------------------------------
+//
+//              on_clicked_start()
+//
+//     Start or stop the GLLIN.
+//
+//------------------------------------------------------------------------------
+
+extern void page_stress_set_report_name(void);
+extern void page_pm_batch_done();
+
+void on_clicked_start(GtkWidget* widget, gpointer data)
+{
+    widget = startWidget;
+    const char* err;
+
+    char buf[128];
+
+
+    g_print("START button. GLLIN %srunning\n", (gllinRunning) ? "" : "not ");
+    testStartTime[0] = 0;
+
+    if (gllinRunning)
+    {
+        gllin_stop();
+        page_pm_batch_done();
+        return;
+    }
+
+    err = gllin_detect();
+    if (err)
+    {
+        g_print("gllin_detect %s\n", err);
+        NMEA_MSG(err);
+        return;
+    }
+
+    doing_ptf = GPOINTER_TO_INT(data);
+    err = gllin_start();
+    if (err)
+    {
+        NMEA_MSG(err);
+        return;
+    }
+
+    gllinRunning = true;
+
+    clearStats();
+    page_stress_set_report_name();
+    page_main_format_date(previousTestTime, true);
+    sprintf(buf, "Started GPS%s%s%s\nat %s\n",
+                (doing_ptf)    ? " one fix"  : " periodic",
+                (doing_batch)  ? " (batch)"  : "",
+                (doing_stress) ? " (stress)" : "",
+                previousTestTime);
+    NMEA_MSG(buf);
+    agps_cb_start(0);
+    page_pm_batch_start();
+    gtk_button_set_label(GTK_BUTTON(widget), "Power off");
+    gtk_widget_set_sensitive(ptfWidget, false);
+}
+
+void
+page_main_done()
+{
+    // Nothing to do at the end of the NMEA epoch?
+    // Might be nice to rotate a little roundel or blink an LED, etc.
+    // But then we should put it on all pages....
+}
+
+#if 0           // Only for stress test future feature.
+
+//      "queue up" the need to stop for polling by the main GTK thread
+//      This is to prevent the need to thread-protect everything.
+//
+// Caution:  called from a timer thread, so all called GTK+ widgets
+//      must be protected by gdk_threads_enter() and gdk_threads_leave()
+
+static bool need_to_stop = false;
+
+void
+page_main_schedule_stop()
+{
+    need_to_stop = true;
+}
+
+void
+page_main_poll_for_stop()
+{
+    if (!need_to_stop) return;
+    need_to_stop = false;
+    const char* msg = "stopped";
+    if (gllinRunning)
+    {
+        msg = "stopping...";
+        on_clicked_start(0, 0);
+    }
+    page_stress_msg(msg);
+}
+
+//      Stress test calls here to start/stop the GLLIN.
+//
+// Caution:  called from a timer thread, so all called GTK+ widgets
+//      must be protected by gdk_threads_enter() and gdk_threads_leave()
+
+void
+page_main_gllin(bool start)
+{
+    const char* msg = "";
+    if (start)
+    {
+        if (gllinRunning)
+        {
+            msg = "Running";
+        }
+        else
+        {
+            msg = "starting...";
+            on_clicked_start(0, 0);
+        }
+    }
+    else
+    {
+        msg = "stopping...";
+        page_main_schedule_stop();
+        page_main_poll_for_stop();              // remove if g_timeout cb needs mutex
+    }
+    page_stress_msg(msg);
+}
+
+#endif 
+
+void on_clicked_exit(GtkWidget* widget, gpointer data)
+{
+    g_print("EXIT button\n");
+    agps_stop();
+    gtk_main_quit();
+}
+
+void on_clicked_reset(GtkWidget* widget, gpointer data)
+{
+	char c = GPOINTER_TO_INT(data);
+
+	//printf("performing %c reset\n", c);
+
+	clearStats();
+	gllin_reset(c);
+}
+
+static gboolean
+expose_main_event(GtkWidget* w, GdkEventExpose* event)
+{
+    notebook_expose("MN");
+    return FALSE;
+}
+
+GtkWidget*
+page_main_create(GtkWidget* window)
+{
+    GtkWidget* label;
+    GtkWidget* button2;
+    GtkWidget* vbox;
+    GtkWidget* table;
+
+    //--------------------------------------------------------------------------
+    //          table
+    //--------------------------------------------------------------------------
+    table = gtk_table_new(14, 2, TRUE);
+    gtk_signal_connect(GTK_OBJECT(table), "expose_event",
+                    G_CALLBACK(expose_main_event), table);
+
+    //--------------------------------------------------------------------------
+    //          label
+    //--------------------------------------------------------------------------
+    label = gtk_label_new(page_main_omgui_version());
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 0, 1);
+    gtk_widget_show(label);
+
+    //--------------------------------------------------------------------------
+    //          label
+    //
+    //  All text from the "main" page goes to this agpsLabel
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("Press START to begin GPS");
+    agpsLabel = GTK_LABEL(label);
+    gtk_label_set_justify(agpsLabel, GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 1, 13);
+    gtk_widget_show(label);
+
+    {
+	    GtkWidget *box, *button;
+
+	    box = gtk_hbox_new (FALSE, 0);
+
+	    button = gtk_button_new_with_label("Cold reset");
+	    g_signal_connect(G_OBJECT(button), "clicked",
+			    G_CALLBACK(on_clicked_reset), GINT_TO_POINTER('c'));
+	    gtk_box_pack_start_defaults(GTK_BOX(box), button);
+
+	    button = gtk_button_new_with_label("Warm reset");
+	    g_signal_connect(G_OBJECT(button), "clicked",
+			    G_CALLBACK(on_clicked_reset), GINT_TO_POINTER('w'));
+	    gtk_box_pack_start_defaults(GTK_BOX(box), button);
+
+	    button = gtk_button_new_with_label("Hot reset");
+	    g_signal_connect(G_OBJECT(button), "clicked",
+			    G_CALLBACK(on_clicked_reset), GINT_TO_POINTER('h'));
+	    gtk_box_pack_start_defaults(GTK_BOX(box), button);
+
+	    gtk_widget_show_all(box);
+
+	    gtk_table_attach_defaults(GTK_TABLE (table), box, 0, 2, 12, 13);
+    }
+    //--------------------------------------------------------------------------
+    //          range controls
+    //--------------------------------------------------------------------------
+    create_range_controls(window, table, false);
+
+    //--------------------------------------------------------------------------
+    //          box for all the buttons
+    //--------------------------------------------------------------------------
+    GtkWidget* box = gtk_hbox_new (FALSE, 0);
+
+    //--------------------------------------------------------------------------
+    //          start periodic button
+    //--------------------------------------------------------------------------
+    GtkWidget* button = gtk_button_new_with_label("Power on");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_start), GINT_TO_POINTER(0));
+    gtk_widget_show(button);
+    startWidget = button;
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 1);
+
+    //--------------------------------------------------------------------------
+    //          PTF button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("One Fix");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_start), GINT_TO_POINTER(1));
+    gtk_widget_show(button);
+    ptfWidget = button;
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 1);
+
+    //--------------------------------------------------------------------------
+    //          exit button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("Exit");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                    G_CALLBACK(on_clicked_exit), NULL);
+    gtk_widget_show(button);
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 1);
+
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 0, 2, 13, 14);
+    gtk_widget_show(box);
+
+    gtk_widget_show(table);
+    return table;
+    test_name[0] = 0;
+}
+
+extern void pm_report(FILE* f, bool stress);
+
+void
+page_main_report(FILE* f)
+{
+    fprintf(f, "GPS is %s\n", (gllinRunning) ? "Running": "Stopped");
+    pm_report(f, false);
+    fprintf(f, "%s\n", gtk_label_get_text(agpsLabel));
+}

Added: developers/olv/openmoko-agpsui2/src/page_map.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_map.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_map.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,1687 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "agps.h"
+#include "sv_bar.h"
+
+// #define OPT_TEST_AVERAGE
+#undef  OPT_TEST_AVERAGE
+
+#undef  DEBUG_PAGE_MAP
+
+#ifdef  OPT_TEST_AVERAGE
+#define DEBUG_PAGE_MAP
+#endif  
+
+static GtkAdjustment* adj_center;
+static GtkButton*     button_style;
+static GtkWidget*     scale_center;
+
+static int adj_upper = 0;
+static int adj_lower = 1;
+
+static void haveNewPosition(int n);
+
+//------------------------------------------------------------------------------------
+//
+//              page_map.cpp
+//
+//      Plot the GPS positions in a window.
+//      Follow the first, last, and average position.
+//      Valid for -88 to +88 degrees.
+//
+//------------------------------------------------------------------------------------
+
+class lla;
+const double PI = 3.1415926535;
+static double pixels_per_meter;
+static void MAP_draw_position(lla* p, bool suppress = true);
+static void MAP_recompute_xy_pixels(const char* msg);
+void page_MAP_init();
+static void MAP_draw_avg_circle(lla* p);
+GtkLabel* map_label;
+extern int fix_good;
+
+static GdkGC* blue_gc = 0;
+static GdkGC* grey_gc = 0;
+
+static GtkDrawingArea* MAP;
+static GdkPixmap*      MAP_PIX = 0;
+bool mph = false;
+static PangoLayout* MAP_text;
+
+//      KLUDGE for A3 or larger fonts only:
+// bool large_font  = true;
+// bool a3_hardware = true;
+#define large_font  1
+#define a3_hardware 1
+
+extern GdkGC* alloc_color(GdkPixmap* pm, const char* color);
+extern void notebook_expose(const char* pageName);
+static double meter_scale();
+void scale_init(GtkScale* scale);
+static void MAP_draw_all_points();
+void page_MAP_alloc_colors();
+static void MAP_redraw();
+static void MAP_draw_lla();
+void page_MAP_have_lla(double lon, double lat, int alt, int heading, int speed, int time);
+static void MAP_draw_scale(double mult, int meters, int nDividers);
+
+static bool map_have_new_pos = false;
+
+static int lla_x0;
+static int lla_y0;
+
+#define MAX_X   ((1 << 15) - 1)
+#define MIN_X   (-MAX_X)
+#define MAX_Y   MAX_X
+#define MIN_Y   MIN_X
+#define SCREEN_WIDTH   476
+#define SCREEN_HEIGHT  400
+
+
+//------------------------------------------------------------------------------------
+//
+//      Class lla
+//
+//  Save the longitude and latitude.
+//  (the altitude, heading, speed, time are also saved).
+//  Convert LLA one time to meters.
+//  Convert to an integer pixel offset from the previous point when
+//  the map scale changes.
+//
+//------------------------------------------------------------------------------------
+
+class lla
+{
+public:
+    lla() : time(0)
+    {
+    };
+
+    lla(double lon_, double lat_, int alt_, int head, int sp_, unsigned long t_)
+        :
+                lon(lon_),
+                lat(lat_),
+                alt(alt_),
+                heading(head),
+                speed(sp_),
+                time(t_)
+    {
+    };
+
+    void init(double lon_, double lat_, int alt_, int head, int sp_, unsigned long t_)
+    {
+        lon = lon_;
+        lat = lat_;
+        alt = alt_;
+        heading = head;
+        speed = sp_;
+        time = t_;
+        compute_xy_meters();
+        last = *this;
+    };
+
+    ~lla()
+    {
+    };
+
+    void compute_xy_meters(void);
+    void compute_xy_meters_abs(lla* p);
+    void compute_xy_pixels(const char* msg = 0);
+
+    double lon;
+    double lat;
+    double delta_lon;
+    double delta_lat;
+
+    double meters_x;    // relative to previous point.
+    double meters_y;    // relative to previous point.
+
+    int pixels_x;       // relative to previous point.
+    int pixels_y;
+
+    int    alt;         // meters
+    int    heading;     // 0=N  90=E  180=S  270=W
+    int    speed;       // km/h
+    unsigned long time; // ms into the GPS week.
+
+    static void restart(void)
+    {
+        prev = 0;
+    }
+    static lla first;
+
+    static lla* lastPoint()
+    {
+        return &last;
+    };
+
+private:
+    static lla* prev;
+    static lla  last;
+};
+
+#ifdef  DEBUG_PAGE_MAP
+// #define DEBUG_F(f)     printf("    " #f " %f\n", f)
+#define DEBUG_F(f)
+#else
+#define DEBUG_F(f)
+#endif
+
+enum
+{
+#ifdef OPT_TEST_AVERAGE
+    MAX_LLA = 7
+#else
+    MAX_LLA = 2000
+#endif
+};
+
+lla avg_lla;
+lla LLA[MAX_LLA];
+static int nLLA = 0;
+static int indexLLA = 0;
+
+static double sum_lon;
+static double sum_lat;
+// static int    sum_alt = 0;
+
+lla  lla::last;
+lla  lla::first;
+lla* lla::prev = 0;
+
+void lla::compute_xy_meters()
+{
+    if (prev)
+    {
+        compute_xy_meters_abs(prev);
+    }
+    else
+    {
+        compute_xy_meters_abs(this);
+        first = *this;
+    }
+    last = *this;
+    prev = this;
+}
+
+//------------------------------------------------------------------------------------
+//
+//      Class MeterScale
+//
+//  Here are all the choices of what you can select with the +/- buttons.
+//
+//------------------------------------------------------------------------------------
+
+struct MeterScale
+{
+    enum
+    {
+        SCALE_1x1  =  9
+    };
+    double scale;               // Pixels/meter
+    int ruler_meters;
+    int ruler_dividers;
+    const char* name;
+};
+
+MeterScale scales[] =
+{
+    { 50, 2, 2, "x50" },           // 0
+    { 32, 5, 5, "x32" },
+    { 20, 5, 5, "x20" },
+    { 16, 10, 5, "x16" },
+
+    { 10, 10, 5, "x10" },           // 4
+    {  8, 20, 4, "x8"  },
+
+    {  5, 20, 4, "x5"  },           // 6
+    {  4, 20, 4, "x4"  },
+    {  2, 50, 5, "x2"  },
+
+    { 1.0,  100, 5, "x1"  },           // 9
+
+    { 0.5,  200, 4, "/2"  },           // 10
+    {  .2,  500, 5, "/5"  },
+    {  .1,  1000, 5, "/10" },
+
+    { .05,  2000,  4, "/20"  },        // 13
+    { .02,  5000,  5, "/50"  },
+    { .01,  10000, 5, "/100" },
+
+    { .005,   20000,  5, "/200" },     // 16
+    { .002,   50000,  5, "/500" },
+    { .001,   100000, 5, "/1k"  },
+
+    { .0005,  200000,  4, "/2k"  },    // 19
+    { .0002,  500000,  5, "/5k"  }
+};
+#define MAX_SCALES (sizeof(scales) / sizeof(*scales))
+
+static int scale_index = MeterScale::SCALE_1x1;
+
+//-------------------------------------------------------------------------------------
+//
+//              testAverage()
+//
+//-------------------------------------------------------------------------------------
+
+#ifdef OPT_TEST_AVERAGE
+static bool
+testAverage()
+{
+    static bool average_done = false;
+    static bool been_here    = false;
+
+    if (been_here) return average_done;
+    been_here = true;
+
+    page_MAP_have_lla(0.000010, 0.000010, 50, 12, 13, 12351);
+    page_MAP_have_lla(0.000020, 0.000020, 50, 12, 13, 12352);
+    page_MAP_have_lla(0.000030, 0.000030, 50, 12, 13, 12353);   // Average/5
+    page_MAP_have_lla(0.000040, 0.000040, 50, 12, 13, 12354);
+    page_MAP_have_lla(0.000050, 0.000050, 50, 12, 13, 12355);
+
+    page_MAP_have_lla(0.000210, 0.000290, 50, 12, 13, 12356);
+    page_MAP_have_lla(0.000220, 0.000280, 50, 12, 13, 12357);
+    page_MAP_have_lla(0.000250, 0.000250, 50, 12, 13, 12358);   // Average/5
+    page_MAP_have_lla(0.000280, 0.000220, 50, 12, 13, 12359);
+    page_MAP_have_lla(0.000290, 0.000210, 50, 12, 13, 12360);
+
+    average_done = true;
+    return average_done;
+}
+
+#define TEST_AVERAGE()  testAverage()
+// #define TEST_AVERAGE()
+#else
+#define TEST_AVERAGE()     false
+#endif
+
+//------------------------------------------------------------------------------
+//
+//      IMPORTANT NOTE:
+//
+//      This code is intended ONLY to show relative positions
+//      of lat/lon on an x,y pixmap to look for GPS problems.
+//      It is NOT to be used for any accurate mapping
+//      to reference points, reference to any geoid, or any
+//      form of navigation.
+//
+//------------------------------------------------------------------------------
+
+void lla::compute_xy_meters_abs(lla* p)
+{
+#ifdef  DEBUG_PAGE_MAP
+    printf("compute_xy_meters[%f %f]-[%f %f]", lon, lat, p->lon, p->lat);
+#endif
+
+    double average_lat = (p->lat + lat)/2.0;            DEBUG_F(average_lat);
+    double rad_lat     = average_lat * PI / 180.0;      DEBUG_F(rad_lat);
+
+    double m = 111132.09;                               DEBUG_F(m);
+    m -= 566.05 * cos(2.0 * rad_lat);                   DEBUG_F(m);
+    m += 1.2*cos(4*rad_lat);                            DEBUG_F(m);
+
+    delta_lat = lat - p->lat;                           DEBUG_F(delta_lat);
+    meters_y = delta_lat * m;                           DEBUG_F(meters_y);
+
+    double pp = 111415.13 * cos(rad_lat) - 94.55*cos(3*rad_lat); DEBUG_F(pp);
+    delta_lon = lon - p->lon;                           DEBUG_F(delta_lon);
+    if (delta_lon <= -180.0)
+    {
+        delta_lon += 360.0;                             // printf("#%f#", delta_lon);
+    }
+    else if (delta_lon > 180.0)
+    {
+        delta_lon -= 360.0;                             // printf("$%f$", delta_lon);
+    }
+    meters_x = delta_lon * pp;                          DEBUG_F(meters_x);
+
+#ifdef  DEBUG_PAGE_MAP
+    printf("= [%f %f]  ", delta_lon, delta_lat);
+    printf("= {%f %f}m\n", meters_x,  meters_y );
+#endif
+}
+
+void
+lla::compute_xy_pixels(const char* msg)
+{
+    // The negative sign on the Y represents the GTK+ coordinate system
+    // where X increases to the right and Y increases as you go lower
+    // on the screen.
+    pixels_x =  static_cast<int> (pixels_per_meter * meters_x);
+    pixels_y = -static_cast<int> (pixels_per_meter * meters_y);
+#ifdef  DEBUG_PAGE_MAP
+    if (msg)
+    {
+        printf("compute_xy_pixels(%s) (%d %d) = %f x {%f %f}\n",
+                msg,
+                pixels_x, pixels_y, pixels_per_meter,
+                meters_x, meters_y);
+    }
+#endif
+}
+
+static void
+printLLA()
+{
+}
+
+static lla*
+addLLA()
+{
+    int old_n = nLLA;
+    lla* result = LLA + indexLLA;
+    if (++indexLLA >= MAX_LLA) indexLLA = 0;
+
+    if (++nLLA > MAX_LLA)
+    {
+        nLLA     = MAX_LLA;             // Limit ourselves to our LLA array size.
+        sum_lon -= result->lon;         // The average is over what we have in
+        sum_lat -= result->lat;         // the array, so remove older items from
+        // sum_alt -= result->alt;      // the running average.
+#ifdef DEBUG_PAGE_MAP
+        printf("SUB [%f %f]\n", result->lon, result->lat);
+#endif
+        //  Since we're about to wipe out this item, make sure the *next*
+        //  item is still tracked relative to the initial position.
+        //  To keep it simple, reassign the initial position to be the next
+        //  position:
+
+        lla* next = LLA + indexLLA;
+        next->meters_x = 0;
+        next->meters_y = 0;
+        next->delta_lon = 0;
+        next->delta_lat = 0;
+        lla::first = *next;
+    }
+
+#ifdef DEBUG_PAGE_MAP
+    printf("have_LLA %d --> %d %d\n", old_n, nLLA, fix_good);
+#endif
+    haveNewPosition(fix_good);
+
+    return result;
+}
+
+//------------------------------------------------------------------------------
+//
+//      lla iterator
+//
+//  OpenMoko apparently lacks <deque> and <algorithm>, so here is a hacked-version
+//  of some iterators for the lla{} vector.
+//
+//------------------------------------------------------------------------------
+
+static lla* pEnd;
+static lla* pCur;
+static lla* pWrap = LLA + MAX_LLA;
+
+lla* lla_next()
+{
+    if (++pCur >= pWrap)
+    {
+        pCur = LLA;
+    }
+    return pCur;
+}
+
+lla* lla_pointN(int n)
+{
+    int i = n;
+    if (nLLA >= MAX_LLA) i = (indexLLA + i) % MAX_LLA;
+
+    lla* r = LLA + i;
+#ifdef  DEBUG_PAGE_MAP
+    printf("lla_pointN(%d) LLA[%d]=[%f %f]\n", n, i, r->lon, r->lat);
+#endif
+    return r;
+}
+
+bool lla_last()
+{
+    return (pCur == pEnd);
+}
+
+lla* lla_begin()
+{
+    if (!nLLA) return 0;
+    pCur = LLA;
+    pEnd = LLA + indexLLA;
+    if (nLLA >= MAX_LLA)
+    {
+        pCur = LLA + indexLLA;
+        pEnd = pCur;
+        // if (++pCur >= pWrap)
+        if (pCur >= pWrap)
+        {
+            pCur = LLA;
+        }
+    }
+    return pCur;
+}
+
+//------------------------------------------------------------------------------
+//
+//      Class TrackStyle
+//
+//  Follow the first, average, or last position.
+//
+//------------------------------------------------------------------------------
+
+class TrackStyle
+{
+public:
+    enum TrackStyleEnum
+    {
+        POINT_0 = 0,
+        AVERAGE,
+        POINT_N,
+        POINT_LAST,
+        STYLE_MAX
+    };
+
+    static bool increment(void);
+    static const char* getName(char* buf);
+    static const char* getLabel(void);
+    static lla* getReference(void);
+    static lla* getReference(TrackStyleEnum style);
+    static TrackStyleEnum getStyle(void);
+    static bool NewPositionCenter(int i);
+
+    TrackStyleEnum style;
+    const char*    label;
+    const char*    name;
+
+private:
+    static TrackStyle styles[STYLE_MAX];
+    static int index;
+    static int point_n;
+    static lla* reference_position;
+};
+
+static lla lla_n;           // the Nth point.
+
+lla*
+TrackStyle::getReference(TrackStyleEnum i)
+{
+    lla* r = 0;
+    switch (i)
+    {
+    default:
+    case POINT_0:
+        break;
+    case AVERAGE:
+        r = &avg_lla;
+        break;
+    case POINT_N:
+        // Convert the intuitive, user-based index that starts at 1.
+        // into internal point index "point_n" which is 0-based
+        lla_n = *lla_pointN(point_n-1);
+        r     = &lla_n;
+        break;
+    case POINT_LAST:
+        r = lla::lastPoint();
+        break;
+    }
+    return r;
+}
+
+lla*
+TrackStyle::getReference(void)
+{
+    return getReference(styles[index].style);
+}
+
+int  TrackStyle::index = TrackStyle::AVERAGE;   // Default tracking style
+lla* TrackStyle::reference_position = 0;
+int TrackStyle::point_n;
+
+TrackStyle::TrackStyleEnum TrackStyle::getStyle()
+{
+    return styles[index].style;
+}
+
+TrackStyle TrackStyle::styles[TrackStyle::STYLE_MAX] =
+{
+    {TrackStyle::POINT_0,    "First","First Fix"},
+    {TrackStyle::AVERAGE,    "Avg",  "Average"  },
+    {TrackStyle::POINT_N,    "Fix",  "Fix #%d"   },
+    {TrackStyle::POINT_LAST, "Last", "Last Fix" }
+};
+
+static void
+haveNewPosition(int n)
+{
+    adj_upper = n;
+    const char* msg = 0;
+    if (TrackStyle::getStyle() == TrackStyle::POINT_LAST)
+    {
+        msg = "value";
+    }
+    g_object_set(G_OBJECT(adj_center),
+                "upper", (gdouble) n,
+                msg,     (gdouble) n,
+                0);
+    gtk_adjustment_changed(adj_center);
+    if (msg)
+    {
+        gtk_adjustment_value_changed(adj_center);
+    }
+    if (n > MAX_LLA)
+    {
+        //------------------------------------------------
+        //
+        // The LLA array is full, and we've wrapped around.
+        // So the user will see numbers larger, but internally,
+        // we have to map them as shown:
+        //       AVERAGE          FIRST         LAST
+        // user: n-MAX_LLA-1      n-MAX_LLA     n
+        // LLA[] 0                1             MAX_LLA
+        //
+        //------------------------------------------------
+
+        adj_lower = n - MAX_LLA;
+        g_object_set(G_OBJECT(adj_center), "lower", (gdouble) adj_lower, 0);
+    }
+}
+
+const char* TrackStyle::getLabel(void)
+{
+    return styles[index].label;
+}
+
+const char* TrackStyle::getName(char* buf)
+{
+    sprintf(buf, styles[index].name, point_n);
+    return buf;
+}
+
+bool TrackStyle::increment(void)
+{
+    if (++index >= STYLE_MAX)
+    {
+        index = POINT_0;
+    }
+    return (index == POINT_N);
+}
+
+bool
+TrackStyle::NewPositionCenter(int adj)
+{
+    bool rc = true;
+
+    if (adj == point_n)
+    {
+        // No change, so this is a self-induced jump!
+        printf("NewPositionCenter(%d) no change\n", adj);
+        return rc;
+    }
+
+    lla* p = lla_pointN(adj - 1);
+
+    //  Moved to the 1st position, so just go there directly.
+    if (lla_begin() == p)
+    {
+        point_n = adj;
+        printf("NewPositionCenter(%d) first\n", adj);
+        return rc;
+    }
+
+    int new_adj = adj;
+    if (adj < point_n)   // go backwards, but don't go past the start.
+    {
+        int lower_limit = fix_good - MAX_LLA;
+        if (lower_limit < 0) lower_limit = 1;
+
+        // Since we're going backwards, look in the *NEXT* position
+        // to see if we have a position change.
+        p = lla_pointN(new_adj);
+
+        while (p->pixels_x == 0 && p->pixels_y == 0)
+        {
+            --new_adj;
+            if (new_adj < lower_limit)
+            {
+                printf("NewPositionCenter(%d) first %d\n", adj, new_adj);
+                rc = false;
+            }
+            p = lla_pointN(new_adj);
+        }
+    }
+    else                // go forwards, but don't go past the end.
+    {
+        while (p->pixels_x == 0 && p->pixels_y == 0)
+        {
+            ++new_adj;
+            if (new_adj > fix_good)
+            {
+                printf("NewPositionCenter(%d) last %d\n", adj, new_adj);
+                return false;
+            }
+            p = lla_pointN(new_adj - 1);
+        }
+    }
+
+    point_n = new_adj;
+    if (new_adj != adj) rc = false;
+
+    if (!rc)
+    {
+        //      Since we're skipping points, don't
+        //      update now:  expect to be called to do the update.
+        g_object_set(G_OBJECT(adj_center), "value", (gdouble) new_adj, 0);
+        gtk_adjustment_value_changed(adj_center);
+        printf("NewPositionCenter(%d) skip to %d\n", adj, new_adj);
+    }
+    return rc;
+}
+
+static int pixel_offset_x;
+static int pixel_offset_y;
+
+static void
+centerOfWindow(int& x, int& y)
+{
+    const int screen_center_x = 476/2;
+    const int screen_center_y = 400/2;
+
+    x = screen_center_x;
+    y = screen_center_y;
+}
+
+const char*
+formatLL(double lon, double lat)
+{
+    char ew = 'E';
+    char ns = 'N';
+
+    if (lon < 0.0) ew = 'W';
+    if (lat < 0.0) ns = 'S';
+
+    static char buf[64];
+    sprintf(buf, "%f %c  %f %c", lon, ew, lat, ns);
+    return buf;
+}
+
+//-----------------------------------------------------------------------------------
+//
+//              computePixelBaseline()
+//
+//      The pixel baseline is added to each pixels_x,pixels_y of the lla{}.
+//      It is:
+//      a)  position[0] (or 0,0) + "screen center" 
+//          When the center is the first position fix.
+//      b)  position[0]-avg + "screen center" 
+//          When the center is the average position.
+//      c)  position[0]-position[LAST] + "screen center" 
+//          When the center is the last position.
+//      d)  position[0]-position[n] + "screen center" 
+//          When the center is the position[n].
+//
+//      Since position[N].meters_x and .pixels_x are computed relative
+//      to position[N-1], we need to compute a temporary:
+//              temp_lla = position[N] - position[0]
+//
+//-----------------------------------------------------------------------------------
+
+void
+computePixelBaseline()
+{
+    centerOfWindow(pixel_offset_x, pixel_offset_y);
+
+    lla* r = TrackStyle::getReference();
+
+    //-----------------------------------------------------------------
+    //  If we have a relative lla to use, then figure out how far it is
+    //  from [0,0].
+    //-----------------------------------------------------------------
+
+    if (r)
+    {
+        char buf0[64];
+        const char* n = TrackStyle::getName(buf0);
+
+        r->compute_xy_meters_abs(&lla::first);
+        r->compute_xy_pixels(n);
+#ifdef  DEBUG_PAGE_MAP
+        printf("baseline (%s)-first = (%d %d) - (%d %d) = (%d %d)\n",
+                    buf0, 
+                    pixel_offset_x, pixel_offset_y,
+                    r->pixels_x, r->pixels_y,
+                    pixel_offset_x - r->pixels_x,
+                    pixel_offset_y - r->pixels_y);
+#endif
+        pixel_offset_x -= r->pixels_x;
+        pixel_offset_y -= r->pixels_y;
+    }
+    else
+    {
+        // printf("baseline FIRST = (%d %d)\n", pixel_offset_x, pixel_offset_y);
+    }
+    if (r != &avg_lla)
+    {
+        // printf("redo(avg) ");
+        avg_lla.compute_xy_meters_abs(&lla::first);
+        avg_lla.compute_xy_pixels("redo(avg)");
+    }
+}
+
+//-----------------------------------------------------------------------------------
+//
+//      set_fix_label()
+//
+//-----------------------------------------------------------------------------------
+
+static void
+set_fix_label()
+{
+    lla* p = TrackStyle::getReference();
+    if (!p) p = &lla::first;
+
+    char buf0[64];
+    char buf1[128];
+    sprintf(buf1, "%s %s #%d",
+                        TrackStyle::getName(buf0),
+                        formatLL(p->lon, p->lat),
+                        fix_good);
+    gtk_label_set_text(map_label, buf1);
+}
+
+//-----------------------------------------------------------------------------------
+//
+//      page_MAP_have_lla()
+//
+//  nmea.cpp sends us positions when they arrive from the NMEA input.
+//  Create an lla & save it.
+//
+//-----------------------------------------------------------------------------------
+
+void
+page_MAP_have_lla(      double lon, double lat,
+                        int alt,
+                        int heading, int speed, int time)
+{
+    if (TEST_AVERAGE()) return;
+
+#ifdef DEBUG_PAGE_MAP
+    printf("page_MAP_have_lla [%f %f]\n", lon, lat);
+#endif
+
+    lla* p = addLLA();
+    p->init(lon, lat, alt, heading, speed, time);
+
+    bool allowSuppress = true;
+    if (nLLA == 1)
+    {
+        allowSuppress = false;
+        sum_lon = lon;
+        sum_lat = lat;
+    }
+    else
+    {
+        sum_lon += p->lon;
+        sum_lat += p->lat;
+    }
+
+#ifdef DEBUG_PAGE_MAP
+    printf("ADD [%f %f] = \n", p->lon, p->lat);
+    printf("sum [%f %f] / %d\n", sum_lon, sum_lat, nLLA);
+#endif
+
+    // Compute the average position:
+    avg_lla.lon = sum_lon / (double) nLLA;
+    if (avg_lla.lon > 180.0)        avg_lla.lon -= 360.0;
+    else if (avg_lla.lon <= -180.0) avg_lla.lon += 360.0;
+
+    avg_lla.lat =  sum_lat           / (double) nLLA;
+    // avg_lla.alt = (sum_alt + nLLA/2) /          nLLA;
+
+#ifdef DEBUG_PAGE_MAP
+    printf("avg [%f %f]\n", avg_lla.lon, avg_lla.lat);
+#endif
+
+    map_have_new_pos = true;
+
+    //  Only compute pixel baseline if:
+    //  ...   mult changes
+    //  ===>  or if average changes (when centering on the       average)  <===
+    //  ===>  or if newer position  (when centering on the last position)  <===
+    //  ===>  or if newer position  (when we have filled the LLA array  )  <===
+    computePixelBaseline();
+    p->compute_xy_pixels("new lla");
+
+    if (MAP_PIX)
+    {
+        MAP_draw_avg_circle(&avg_lla);          // average is a small circle
+        MAP_draw_position(p, allowSuppress);
+        set_fix_label();
+    }
+}
+
+//------------------------------------------------------------------------------------
+//
+//      MAP_self_test
+//
+//  Create dummy points to exercise the plotting algorithms
+//
+//------------------------------------------------------------------------------------
+
+static const char*
+MAP_self_test()
+{
+    const char* msg = 0;
+
+    // Stub for now:  add some data points!
+    static bool been_here = false;
+    if (!been_here)
+    {
+        been_here = true;
+
+#if 0   // PASS
+        msg = "2-point test case";
+        page_MAP_have_lla(-1.0, -1.0, 50, 0, 0, 126000);
+        page_MAP_have_lla( 1.0,  1.0, 50, 0, 0, 127000);
+#if 0   // PASS
+        msg = "3-point test case";
+        page_MAP_have_lla( 1.1,  1.0, 50, 0, 0, 127000);
+#endif
+#endif
+
+#if 0   // PASS
+        msg = "Local test case";
+        page_MAP_have_lla(-121.000000, 37.000000, 50, 0, 0, 123000);
+        page_MAP_have_lla(-121.000120, 37.000000, 50, 0, 0, 124000);
+        page_MAP_have_lla(-121.000120, 37.001500, 50, 0, 0, 125000);
+        page_MAP_have_lla(-121.000000, 37.001500, 50, 0, 0, 126000);
+        page_MAP_have_lla(-121.000000, 37.000200, 50, 0, 0, 127000);
+#endif
+
+#if 0   // PASS
+        msg = "West test case";
+        page_MAP_have_lla( 0.000030, -0.00050, 50, 0, 0, 123000);
+        page_MAP_have_lla(-0.000120, -0.00050, 50, 0, 0, 124000);
+        page_MAP_have_lla(-0.000120,  0.00050, 50, 0, 0, 125000);
+        page_MAP_have_lla( 0.000030,  0.00050, 50, 0, 0, 126000);
+        page_MAP_have_lla( 0.000030, -0.00045, 50, 0, 0, 127000);
+#endif
+
+#if 0   // PASS        // Test case 1 (wrap around "east pole" 180,0)
+        msg = "East #1 test case";
+        page_MAP_have_lla(-179.99801, -0.000511, 50, 0, 0, 123000);
+        page_MAP_have_lla( 179.99812, -0.000522, 50, 0, 0, 124000);
+        // page_MAP_have_lla(-179.99803, -0.000536, 50, 0, 0, 123000);
+
+#if 0
+        msg = "East #2 test case";
+        page_MAP_have_lla( 179.99813, +0.00053, 50, 0, 0, 125000);
+        page_MAP_have_lla(-179.99794, +0.00054, 50, 0, 0, 126000);
+        page_MAP_have_lla(-179.99805, -0.00050, 50, 0, 0, 127000);
+#endif
+#endif
+
+#if 0   // FAIL           // Test case 1 (wrap around "north pole" 0,90)
+        msg = "North test case\n";
+        page_MAP_have_lla(   0.00101, 89.99500, 50, 0, 0, 123000);
+        page_MAP_have_lla(  90.00102, 89.99500, 50, 0, 0, 124000);
+        page_MAP_have_lla( 179.00103, 89.99500, 50, 0, 0, 125000);
+        page_MAP_have_lla( -90.00104, 89.99500, 50, 0, 0, 126000);
+        page_MAP_have_lla(  -0.99905, 89.99450, 50, 0, 0, 127000);
+#endif
+
+#if 0   // FAIL           // Test case 1 (wrap around "south pole" 0,-90)
+        msg = "South test case\n";
+        page_MAP_have_lla(   0.00100, -89.99500, 50, 0, 0, 123000);
+        page_MAP_have_lla(  90.00100, -89.99500, 50, 0, 0, 124000);
+        page_MAP_have_lla( 179.00100, -89.99500, 50, 0, 0, 125000);
+        page_MAP_have_lla( -90.00100, -89.99500, 50, 0, 0, 126000);
+        page_MAP_have_lla(  -0.99900, -89.99450, 50, 0, 0, 127000);
+#endif
+
+    }
+    return msg;
+}
+
+//-----------------------------------------------------------------------------------
+//
+//      cb_change_center()
+//
+// Adjusting slider to change center position
+//
+//-----------------------------------------------------------------------------------
+
+static void
+cb_change_center(GtkAdjustment* adj)
+{
+    if (TrackStyle::NewPositionCenter((gint) adj->value))
+    {
+        MAP_redraw();
+    }
+}
+
+//-----------------------------------------------------------------------------------
+//
+//      on_map_units_change()
+//
+//  Do nothing (maybe self-test)
+//  Update the page label.
+//
+//-----------------------------------------------------------------------------------
+
+static void
+on_map_units_change()
+{
+    // page_MAP_init();
+    const char* msg = MAP_self_test();
+    if (!msg)
+    {
+        msg = "km/h";
+        if (mph) msg = "mph";
+    }
+    gtk_label_set_text(map_label, msg);
+}
+
+//------------------------------------------------------------------------------
+//
+//      on_clicked_track_style()
+//
+//  Walk through the different tracking styles.
+//
+//------------------------------------------------------------------------------
+
+static void
+on_clicked_track_style(GtkWidget* w, gpointer d)
+{
+    gtk_widget_set_sensitive(GTK_WIDGET(scale_center),
+                             TrackStyle::increment()  );
+    MAP_recompute_xy_pixels("track style change");
+    MAP_redraw();
+}
+
+//------------------------------------------------------------------------------
+//
+//      on_clicked_mph()
+//
+//  GTK+ callback.
+//  Update the system state, and the button.
+//
+//------------------------------------------------------------------------------
+
+static void
+on_clicked_mph(GtkWidget* widget, gpointer data)
+{
+    mph = !mph;
+    gtk_button_set_label(GTK_BUTTON(data), (mph) ? "mph" : "km/h");
+    on_map_units_change();
+}
+
+static void
+MAP_clear()
+{
+    GtkWidget* w = GTK_WIDGET(MAP);
+    gdk_draw_rectangle(MAP_PIX, w->style->white_gc, TRUE,
+                       0, 0,
+                       w->allocation.width,
+                       w->allocation.height);
+}
+
+static gboolean
+configure_MAP_event(GtkWidget* w, GdkEventConfigure* event)
+{
+    if (MAP_PIX)
+    {
+        g_object_unref(MAP_PIX);
+    }
+
+    //--------------------------------------------------------------------------
+    //          pixmap to make the window easier to draw
+    //--------------------------------------------------------------------------
+    MAP_PIX = gdk_pixmap_new(w->window,
+                            w->allocation.width,
+                            w->allocation.height, -1);
+    MAP_clear();
+    return TRUE;
+}
+
+static gboolean
+expose_MAP_event(GtkWidget* w, GdkEventExpose* event)
+{
+    notebook_expose("MP");
+    GdkRectangle& a = event->area;
+    gdk_draw_drawable(w->window,
+                      w->style->fg_gc[GTK_WIDGET_STATE(w)],
+                      MAP_PIX, a.x, a.y, a.x, a.y, a.width, a.height);
+    return FALSE;
+}
+
+static GdkGC* 
+getGC(bool used)
+{
+    GdkGC* gc = grey_gc;
+    if (used)
+    {
+        gc = blue_gc;                   // used SV is colored blue
+    }
+    if (!gc)
+    {
+        gc = GTK_WIDGET(MAP)->style->black_gc;
+    }
+    return gc;
+}
+
+void
+page_MAP_alloc_colors()
+{
+    if (!MAP_PIX) return;
+    if (!blue_gc) blue_gc = alloc_color(MAP_PIX, "Blue");
+    if (!grey_gc) grey_gc = alloc_color(MAP_PIX, "SlateGrey");
+}
+
+//------------------------------------------------------------------------------
+//
+//      MAP_draw_avg_circle
+//
+//  Draw the little "average" circle at the point.
+//
+//------------------------------------------------------------------------------
+
+static void
+MAP_draw_avg_circle(lla* p)
+{
+    int rect = 5;
+
+    int x = pixel_offset_x + p->pixels_x;
+    int y = pixel_offset_y + p->pixels_y;
+
+    if (x > SCREEN_WIDTH || x < 0 || y > SCREEN_HEIGHT || y < 0)
+    {
+        // printf("circle [%f %f] {%f %f} (%d %d) OFF SCREEN\n",
+        //         p->lon, p->lat,
+        //         p->meters_x, p->meters_y,
+        //         x, y);
+        return;
+    }
+
+    //----------------------------------------------
+    //          Draw 11x11 circle
+    //----------------------------------------------
+
+    int size = 2*rect + 1;
+#ifdef  DEBUG_PAGE_MAP
+    printf("MAP circle (%d %d)==>(%d %d) size %d\n", x, y, x-rect, y-rect, size);
+#endif
+    gdk_draw_arc(MAP_PIX, GTK_WIDGET(MAP)->style->black_gc, FALSE,
+            x - rect, y - rect, size, size, 0, 360 * DEGREE_64);
+}
+
+//-----------------------------------------------------------------------------
+//
+//              Draw the positions and lines between them
+//
+//      (if they are not too close)
+//
+//-----------------------------------------------------------------------------
+
+static int accum_x;
+static int accum_y;
+
+static void
+MAP_reset_position_accum()
+{
+    accum_x = 0;
+    accum_y = 0;
+}
+
+static void
+MAP_draw_position(lla* p, bool suppress)
+{
+    //------------------------------------------------------
+    //  Suppress everything if the point is too close to the
+    //  previous position.
+    //  The distance is calculated as dx*dx + dy*dy, where
+    //          dx == p->pixels_x and
+    //          dy == p->pixels_y in meter units.
+    //  If we drop a point, then accumulate the delta(x,y) for
+    //  the next point.
+    //------------------------------------------------------
+
+    const int rect = 5;
+    const int half_rect_sq = (rect/2) * (rect/2);
+
+    int x = p->pixels_x + accum_x;
+    int y = p->pixels_y + accum_y;
+
+#ifdef DEBUG_PAGE_MAP
+    printf("MAP draw pos (%d %d)", p->pixels_x, p->pixels_y);
+    if (accum_x || accum_y) printf("+(%d %d) ", accum_x, accum_y);
+#endif
+
+    if (suppress)
+    {
+        //      We are allowed to suppress this point if the x,y is
+        //      too close to the previous point.
+        int dist = x*x + y*y;
+        if (dist < half_rect_sq)
+        {
+#ifdef DEBUG_PAGE_MAP
+            if (dist) printf(" = %d  TOO CLOSE: suppress", dist);
+            printf("\n");
+#endif
+            accum_x += p->pixels_x;
+            accum_y += p->pixels_y;
+            return;
+        }
+    }
+
+    x += lla_x0;
+    y += lla_y0;
+
+    MAP_reset_position_accum();
+
+    //----------------------------------------------
+    //     The line and position will be grey if it
+    //     exceeds bounds;
+    //----------------------------------------------
+
+    GdkGC* gc = getGC(true);
+    if (x > MAX_X || x < MIN_X || y > MAX_Y || y < MIN_Y)
+    {
+        if (x > MAX_X) x = MAX_X;
+        if (x < MIN_X) x = MIN_X;
+        if (y > MAX_Y) y = MAX_Y;
+        if (y < MIN_Y) y = MIN_Y;
+
+#ifdef DEBUG_PAGE_MAP
+        printf(" ==> (%d %d) > %d..%d bounds exceeded ", x, y, MIN_X, MAX_Y);
+#endif
+        gc = getGC(false);
+    }
+
+    //----------------------------------------------
+    //          Draw the point as a 5x5 rectangle
+    //  Don't draw if off the screen.
+    //----------------------------------------------
+
+    if (x > SCREEN_WIDTH || x < 0 || y > SCREEN_HEIGHT || y < 0)
+    {
+#ifdef DEBUG_PAGE_MAP
+        printf(" > %d..%d : OFF SCREEN", SCREEN_WIDTH, SCREEN_HEIGHT);
+#endif
+    }
+    else
+    {
+        gdk_draw_rectangle(MAP_PIX, gc, TRUE, x - rect/2, y - rect/2, rect, rect);
+#ifdef DEBUG_PAGE_MAP
+        printf(" rect @ [%f %f]", p->lon, p->lat);
+#endif
+    }
+
+    //----------------------------------------------
+    //          Draw the route as a line.
+    //  DO draw if out of bounds, but make it grey.
+    //----------------------------------------------
+
+    if (suppress)
+    {
+        gdk_draw_line(MAP_PIX, gc, lla_x0, lla_y0, x, y);
+#ifdef DEBUG_PAGE_MAP
+        // printf(" line (%d %d)-->(%d %d)", lla_x0, lla_y0, x, y);
+#endif
+    }
+#ifdef DEBUG_PAGE_MAP
+    printf("\n");
+#endif
+
+    lla_x0 = x;
+    lla_y0 = y;
+}
+
+//------------------------------------------------------------------------------------
+//
+//      MAP_draw_all_points()
+//
+//------------------------------------------------------------------------------------
+
+static void
+MAP_draw_all_points()
+{
+    MeterScale& m = scales[scale_index];
+    MAP_draw_scale(m.scale, m.ruler_meters, m.ruler_dividers);
+
+    // printf("MAP_draw_all_points() %d %d\n", indexLLA, nLLA);
+
+    if (!nLLA) return;
+
+    lla_x0 = pixel_offset_x;
+    lla_y0 = pixel_offset_y;
+
+    MAP_draw_avg_circle(&avg_lla);       // average circle
+
+    lla* p = lla_begin();
+    if (!p) return;
+
+    MAP_reset_position_accum();
+#ifdef  DEBUG_PAGE_MAP
+    int i = 0;
+    printf("%d) ", i);
+#endif
+    MAP_draw_position(p, false);        // first point is not suppressed.
+    do
+    {
+        p = lla_next();
+#ifdef  DEBUG_PAGE_MAP
+        printf("%d) ", ++i);
+#endif
+        MAP_draw_position(p);
+    } while (!lla_last());
+
+#if   0                 // DEBUG_PAGE_MAP
+    i = 0;
+    p = lla_begin();
+    do
+    {
+        printf("%d) 0x%x [%f %f]\n", i++, p, p->lon, p->lat);
+        p = lla_next();
+    } while (!lla_last());
+#endif
+}
+
+//-----------------------------------------------------------------------------------
+//
+//      MAP_draw_scale()
+//
+//  Draw the meter scale, text, sub-markers,
+//  circle, and text on the circle.
+//
+//-----------------------------------------------------------------------------------
+
+static void
+MAP_draw_scale(double mult, int meters, int nDividers)
+{
+    GdkGC* gc = getGC(false);
+
+    double width = mult * static_cast<double> (meters);
+    int w = static_cast<int> (width);
+
+    //----------------------------------------------
+    //          Draw the scale
+    //----------------------------------------------
+
+    int x0 = 10;                // Arbitrary scale location choice...
+    int y0 = 20;
+
+    int x1 = x0 + w;
+    int y1 = y0;
+    gdk_draw_line(MAP_PIX, gc, x0, y0, x1, y1);
+    gdk_draw_line(MAP_PIX, gc, x0, y0, x0, y0 + 8);
+    gdk_draw_line(MAP_PIX, gc, x1, y1, x1, y1 + 8);
+
+    //----------------------------------------------
+    //          Draw the sub-scale markers
+    //----------------------------------------------
+
+    int sub = w/nDividers;
+    for (x0 += sub; x0 < x1; x0 += sub)
+    {
+        gdk_draw_line(MAP_PIX, gc, x0, y0, x0, y0 + 4);
+    }
+
+    //----------------------------------------------
+    //          Compute and format the scale text
+    //----------------------------------------------
+
+    char buf[10];
+    if (meters >= 1000) sprintf(buf, "%d km", meters/1000);
+    else                sprintf(buf, "%d m",  meters     );
+
+    //----------------------------------------------
+    //          Draw the scale text
+    //----------------------------------------------
+
+    pango_layout_set_text(MAP_text, buf, -1);
+    int h;
+    pango_layout_get_pixel_size(MAP_text, 0, &h);
+    gdk_draw_layout(MAP_PIX, gc, x1 + 3, y0 - h/2, MAP_text);
+
+    //-------------------------------------------------------------------------
+    //      Draw the radius circle and text
+    //-------------------------------------------------------------------------
+
+    centerOfWindow(x0, y0);
+
+    int size = 2*w + 1;
+    // printf("MAP circle (%d %d)==>(%d %d) size %d\n", x0, y0, x0-w, y0-w, size);
+    gdk_draw_arc(MAP_PIX, gc, FALSE,
+            x0-w, y0-w, size, size, 0, 360 * DEGREE_64);
+    gdk_draw_layout(MAP_PIX, gc, x0 + w + 3, y0 - h/2, MAP_text);
+
+#if 0
+    //----------------------------------------------
+    //          Draw 15x15 cross
+    //----------------------------------------------
+    gdk_draw_line(MAP_PIX, gc, x0-7, y0  , x0+7, y0  );
+    gdk_draw_line(MAP_PIX, gc, x0  , y0-7, x0  , y0+7);
+#else
+    //-------------------------------------------------------------------------
+    //      Experiment with a NxN grey spot in the center.
+    //-------------------------------------------------------------------------
+    size = sub/2;
+    // printf("MAP spot (%d %d)==>(%d %d) size %d\n", x0, y0, x0-w, y0-w, size);
+    gdk_draw_arc(MAP_PIX, gc, TRUE,
+            x0-size-1, y0-size-1, sub, sub, 0, 360 * DEGREE_64);
+#endif
+
+}
+
+GtkLabel* map_scale_label = 0;
+
+
+static void meter_scale_reset()
+{
+    scale_index = 8;
+    pixels_per_meter = scales[scale_index].scale;
+}
+
+static double meter_scale()
+{
+    return scales[scale_index].scale;
+}
+
+//------------------------------------------------------------------------------------
+//
+//      MAP_redraw()
+//
+//------------------------------------------------------------------------------------
+
+static void
+MAP_redraw()
+{
+    // printf("MAP_redraw\n");
+    if (!MAP_PIX) return;
+    page_MAP_alloc_colors();
+
+    MAP_clear();
+    gtk_button_set_label(button_style, TrackStyle::getLabel());
+
+    computePixelBaseline();
+    MAP_draw_all_points();
+    gtk_widget_queue_draw_area(GTK_WIDGET(MAP), 0, 0, 476, 476);
+    map_have_new_pos = false;
+
+    set_fix_label();
+}
+
+//------------------------------------------------------------------------------------
+//
+//      page_MAP_done()
+//
+//------------------------------------------------------------------------------------
+
+void
+page_MAP_done()
+{
+    if (!map_have_new_pos) return;
+    MAP_redraw();
+}
+
+//------------------------------------------------------------------------------------
+//
+//      cb_meter_scale_change()
+//
+//  GTK+ callback when the user pressed [+] or [-].
+//
+//------------------------------------------------------------------------------------
+
+static void
+cb_meter_scale_change(GtkWidget* w, gpointer data)
+{
+    int x = GPOINTER_TO_INT(data);
+    int new_index = scale_index + x;
+    if (new_index < 0) new_index = 0;
+    if (new_index >= MAX_SCALES) new_index = MAX_SCALES - 1;
+    if (new_index == scale_index)
+    {
+        return;         //  nothing changed!
+    }
+    scale_index = new_index;
+
+    MeterScale& ms = scales[scale_index];
+    pixels_per_meter = ms.scale;
+
+    char buf[64];
+    sprintf(buf, "Scale %s", ms.name);
+    gtk_label_set_text(map_scale_label, buf);
+    MAP_recompute_xy_pixels("scale change");
+    MAP_redraw();
+}
+
+//------------------------------------------------------------------------------------
+//
+//      MAP_recompute_xy_pixels()
+//
+//   Since the multiplier changed, we need to recompute the
+//   int x,y = (int) double mult*(double meters_x,double meters_y).
+//
+//------------------------------------------------------------------------------------
+
+static void
+MAP_recompute_xy_pixels(const char* msg)
+{
+    //  Only compute pixel baseline if:
+    //  ===>  mult changes  <===
+    //  ... or if average changes (when centering the average),
+    //  ... or if newer position  (when centering the last position)
+    computePixelBaseline();
+
+    int i = 0;
+    lla* p = lla_begin();
+    if (p) p->compute_xy_pixels(msg);
+    do
+    {
+        p = lla_next();
+        p->compute_xy_pixels(msg);
+    } while (!lla_last());
+}
+
+//------------------------------------------------------------------------------------
+//
+//      page_MAP_init()
+//
+//------------------------------------------------------------------------------------
+
+void
+page_MAP_init()
+{
+    meter_scale_reset();
+    memset(LLA, 0, sizeof(LLA));
+    nLLA = 0;
+    indexLLA = 0;
+    centerOfWindow(lla_x0, lla_y0);
+    sum_lon = 0.0;
+    sum_lat = 0.0;
+    lla::restart();
+}
+
+//------------------------------------------------------------------------------------
+//
+//      page_MAP_create()
+//
+//------------------------------------------------------------------------------------
+
+GtkWidget*
+page_MAP_create(GtkWidget* window)
+{
+    GtkWidget* label;
+    GtkWidget* button;
+    GtkWidget* w;
+    GtkWidget* box;
+    GtkObject* adj;
+    GtkWidget* table;
+
+    //--------------------------------------------------------------------------
+    //          table
+    //--------------------------------------------------------------------------
+    table = gtk_table_new(14, 2, TRUE);
+
+    //--------------------------------------------------------------------------
+    //          label
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("Position Plot");
+    gtk_label_set_justify((GtkLabel*)label, GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 0, 1);
+    gtk_widget_show(label);
+    map_label = GTK_LABEL(label);
+
+    MAP_text = gtk_widget_create_pango_layout(label, "");
+
+    //--------------------------------------------------------------------------
+    //          window for the position plot
+    //--------------------------------------------------------------------------
+    w  = gtk_drawing_area_new();
+    MAP = GTK_DRAWING_AREA(w);
+    gtk_drawing_area_size(MAP, 500, 500);
+
+    gtk_signal_connect(GTK_OBJECT(w), "configure_event",
+                    G_CALLBACK(configure_MAP_event), w);
+
+    gtk_signal_connect(GTK_OBJECT(w), "expose_event",
+                    G_CALLBACK(expose_MAP_event), w);
+
+    gtk_widget_set_events(w, GDK_EXPOSURE_MASK);
+    gtk_table_attach_defaults(GTK_TABLE (table), w, 0, 2, 1, 12);
+    gtk_widget_show(w);
+
+    //--------------------------------------------------------------------------
+    //          Meter scaling
+    //--------------------------------------------------------------------------
+
+    box = gtk_hbox_new(FALSE, 1);
+    gtk_container_set_border_width (GTK_CONTAINER (box), 0);
+
+    label = gtk_label_new ("Scale x1");
+    gtk_widget_show (label);
+    map_scale_label = GTK_LABEL(label);
+    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+
+    button = gtk_button_new_with_label("+");
+    g_signal_connect (G_OBJECT (button), "clicked",
+                      G_CALLBACK (cb_meter_scale_change), (gpointer) -1);
+    gtk_box_pack_start (GTK_BOX (box), button, TRUE, TRUE, 0);
+    gtk_widget_show(button);
+
+    button = gtk_button_new_with_label("-");
+    g_signal_connect (G_OBJECT (button), "clicked",
+                      G_CALLBACK (cb_meter_scale_change), (gpointer) +1);
+    gtk_box_pack_start (GTK_BOX (box), button, TRUE, TRUE, 0);
+    gtk_widget_show(button);
+
+    gtk_widget_show (box);
+
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 0, 2, 12, 13);
+
+    //--------------------------------------------------------------------------
+    //          Box to hold the center style button
+    //          and the position slider.
+    //--------------------------------------------------------------------------
+
+    box = gtk_hbox_new (FALSE, 0);
+    gtk_container_set_border_width (GTK_CONTAINER (box), 0);
+
+    //--------------------------------------------------------------------------
+    //          Track style button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label(TrackStyle::getLabel());
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_track_style), button);
+    gtk_box_pack_start (GTK_BOX (box), button, FALSE, TRUE, 0);
+    gtk_widget_show(button);
+    button_style = GTK_BUTTON(button);
+
+    //--------------------------------------------------------------------------
+    //          Position adjuster
+    //--------------------------------------------------------------------------
+    adj = gtk_adjustment_new(1.0, 1.0, 1.0, 1.0, 1.0, 1.0);
+    g_signal_connect (G_OBJECT (adj), "value_changed",
+                      G_CALLBACK (cb_change_center), (gpointer) adj);
+    adj_center = GTK_ADJUSTMENT(adj);
+    scale_center = gtk_hscale_new(adj_center);
+    scale_init(GTK_SCALE(scale_center));
+    gtk_widget_set_sensitive(scale_center, false);
+    gtk_box_pack_start (GTK_BOX (box), scale_center, TRUE, TRUE, 1);
+    gtk_widget_show (scale_center);
+
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 0, 1, 13, 14);
+    gtk_widget_show (box);
+
+    //--------------------------------------------------------------------------
+    //          km/h or mph
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("mph");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_mph), button);
+    gtk_table_attach_defaults(GTK_TABLE (table), button, 1, 2, 13, 14);
+    gtk_widget_show(button);
+
+    gtk_widget_show(table);
+
+    page_MAP_init();
+    return table;
+}
+
+static lla t;
+
+static void
+page_map_report_dist(FILE* f, const char* msg, lla* p, lla* avg)
+{
+    fprintf(f, "%s position %f  %f", msg, p->lon, p->lat);
+
+    if (avg != p)
+    {
+        t = *p;
+        t.compute_xy_meters_abs(avg);
+        double d = sqrt(t.meters_x*t.meters_x + t.meters_y*t.meters_y);
+        if (d > 0.09) fprintf(f, " %.1f m from average", d);
+    }
+    fprintf(f, "\n");
+}
+
+void
+page_map_report(FILE* f)
+{
+    int n = fix_good;
+    if (n > MAX_LLA) n = MAX_LLA;
+    fprintf(f, "%d positions obtained, %d plotted\n", fix_good, n);
+
+    lla* p0 = lla_begin();
+    lla* pA = TrackStyle::getReference(TrackStyle::AVERAGE);
+    lla* pN = TrackStyle::getReference(TrackStyle::POINT_LAST);
+
+    page_map_report_dist(f, "  First",  p0, pA);
+    page_map_report_dist(f, "Average",  pA, pA);
+    page_map_report_dist(f, "   Last",  pN, pA);
+}

Added: developers/olv/openmoko-agpsui2/src/page_speed.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_speed.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_speed.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,236 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <string.h>
+#include "agps.h"
+#include "sv_bar.h"
+
+// TODO:
+// 1)  Connect the needle to real GPS activities
+// 2)  Add numbers and tick marks to the dials.
+
+void notebook_expose(const char* pageName);
+
+static GtkDrawingArea* speed;
+static GdkPixmap*      speed_PIX = 0;
+static PangoLayout*    speed_text;
+
+static GdkGC* blue_gc = 0;
+static GdkGC* grey_gc = 0;
+
+extern GdkGC* alloc_color(GdkPixmap* pm, const char* color);
+
+static void
+speed_alloc_colors()
+{
+    if (!speed_PIX) return;
+    if (!blue_gc) blue_gc = alloc_color(speed_PIX, "Blue");
+    if (!grey_gc) grey_gc = alloc_color(speed_PIX, "SlateGrey");
+}
+
+static void
+speed_clear()
+{
+    if (!speed_PIX) return;
+    GtkWidget* w = GTK_WIDGET(speed);
+    gdk_draw_rectangle(speed_PIX, w->style->white_gc, TRUE,
+                       0, 0,
+                       w->allocation.width,
+                       w->allocation.height);
+}
+
+static gboolean
+configure_speed_event(GtkWidget* w, GdkEventConfigure* event)
+{
+    if (speed_PIX)
+    {
+        g_object_unref(speed_PIX);
+    }
+
+    //--------------------------------------------------------------------------
+    //          pixmap
+    //--------------------------------------------------------------------------
+    speed_PIX = gdk_pixmap_new(w->window,
+                            w->allocation.width,
+                            w->allocation.height, -1);
+    speed_clear();
+    return TRUE;
+}
+
+static gboolean
+expose_speed_event(GtkWidget* w, GdkEventExpose* event)
+{
+    notebook_expose("SP");
+    if (speed_PIX)
+    {
+        GdkRectangle& a = event->area;
+        gdk_draw_drawable(w->window,
+                      w->style->fg_gc[GTK_WIDGET_STATE(w)],
+                      speed_PIX, a.x, a.y, a.x, a.y, a.width, a.height);
+    }
+    return FALSE;
+}
+
+static GdkGC*
+getGC(bool used)
+{
+    speed_alloc_colors();
+    GdkGC*    gc = grey_gc;
+    if (used) gc = blue_gc;
+    if (!gc)  gc = GTK_WIDGET(speed)->style->black_gc;
+    return gc;
+}
+
+enum
+{
+    CENTER_XY = 3,
+    CENTER_X  = 1,
+    CENTER_Y  = 2,
+    CENTER_NONE = 0,
+
+    ALIGN_BOTTOM = 16,
+    ALIGN_RIGHT  = 32
+};
+
+static void
+speed_draw_text(int x, int y, const char* t,
+                int center = CENTER_XY, GdkGC* gc = 0)
+{
+    if (!gc) gc = getGC(false);
+    pango_layout_set_text(speed_text, t, -1);
+    if (center)
+    {
+        int w;
+        int h;
+        pango_layout_get_pixel_size(speed_text, &w, &h);
+        if      (center & CENTER_X    ) x -= w/2;
+        else if (center & ALIGN_RIGHT ) x -= w;
+        if      (center & CENTER_Y    ) y -= h/2;
+        else if (center & ALIGN_BOTTOM) y -= h;
+    }
+    // printf("speed_draw_text(%d,%d,\"%s\", %d)\n", x, y, t, center);
+    gdk_draw_layout(speed_PIX, gc, x, y, speed_text);
+}
+
+static void
+speed_draw_line(int x0, int y0, int x1, int y1)
+{
+    // printf("speed_draw_line(%d,%d,%d,%d)\n", x0, y0, x1, y1);
+    GdkGC* gc = GTK_WIDGET(speed)->style->black_gc;
+    gdk_draw_line(speed_PIX, gc, x0, y0, x1, y1);
+}
+
+static void
+speed_draw_dial(const char* name, int x, int y)
+{
+    GdkGC* gc = getGC(true);
+
+    int radius = PIXMAP_WIDTH/4 - 3;
+    int width  = radius * 2;
+    int height = width;
+    int arc0 = 0;
+    int arcN = 360 * DEGREE_64;
+    gdk_draw_arc(speed_PIX, gc, FALSE,
+                x+3, y+3,
+                width, height,
+                arc0, arcN);
+
+    int cx = x + PIXMAP_WIDTH/4;
+    int cy = y + PIXMAP_WIDTH/4;
+    speed_draw_text(cx, cy-radius/2, name);
+
+    speed_draw_line(cx,cy,  cx,cy-radius);
+}
+
+static void
+speed_draw_dials()
+{
+    int h = PIXMAP_WIDTH/2;
+
+    speed_draw_dial("SPEED",   0, 0);
+    speed_draw_dial("ALT",     h, 0);
+    speed_draw_dial("HEADING", 0, h);
+    speed_draw_dial("VERTICAL\nSPEED", h, h);
+
+    gtk_widget_queue_draw_area(GTK_WIDGET(speed), 0, 0,
+                               PIXMAP_WIDTH, PIXMAP_WIDTH);
+}
+
+void
+page_speed_done()
+{
+    if (!speed_PIX) return;
+    speed_clear();
+    speed_draw_dials();
+}
+
+GtkWidget*
+page_speed_create(GtkWidget* window)
+{
+    GtkWidget* label;
+    GtkWidget* button;
+    GtkWidget* w;
+    GtkWidget* vbox;
+    GtkWidget* table;
+
+    //--------------------------------------------------------------------------
+    //          table
+    //--------------------------------------------------------------------------
+    table = gtk_table_new(14, 2, TRUE);
+
+    //--------------------------------------------------------------------------
+    //          label
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("Indicators");
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 0, 1);
+    gtk_widget_show(label);
+
+    speed_text = gtk_widget_create_pango_layout(label, "");
+
+    //--------------------------------------------------------------------------
+    //          window for the various dials
+    //--------------------------------------------------------------------------
+    w  = gtk_drawing_area_new();
+    speed = GTK_DRAWING_AREA(w);
+    gtk_drawing_area_size(speed, PIXMAP_WIDTH, PIXMAP_WIDTH);
+
+    gtk_signal_connect(GTK_OBJECT(w), "configure_event",
+                    G_CALLBACK(configure_speed_event), w);
+
+    gtk_signal_connect(GTK_OBJECT(w), "expose_event",
+                    G_CALLBACK(expose_speed_event), w);
+
+    gtk_widget_set_events(w, GDK_EXPOSURE_MASK);
+    gtk_table_attach_defaults(GTK_TABLE (table), w, 0, 2, 1, 14);
+    gtk_widget_show(w);
+
+    gtk_widget_show(table);
+    return table;
+}
+
+void
+page_speed_report(FILE* f)
+{
+    fprintf(f, "Say something about %s/%d\n", __FILE__, __LINE__);
+}

Added: developers/olv/openmoko-agpsui2/src/page_stats.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_stats.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_stats.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,322 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "agps.h"
+#include "sv_bar.h"
+
+// TODO:
+// 1)  Connect the stats items to real GPS activities
+
+void notebook_expose(const char* pageName);
+static void page_stats_fix_time_update(int x);
+enum
+{
+    MASK_TTF = 1,
+    MASK_TTFF = 2
+};
+
+static GtkLabel* wid_ttff;
+static GtkLabel* wid_ttf;
+
+class FixTime
+{
+public:
+    void init();
+    void fix_time(float t);
+    char* report(int n, char* buf) const;
+
+    FixTime(const char* name) : name_(name)
+    {
+        init();
+    };
+
+private:
+    int n_;          // Number of samples
+
+    double min_;
+    double max_;
+
+    double mean_;
+    double S_;
+
+    const char* name_;
+};
+
+void
+FixTime::init()
+{
+    min_  = 99999.0;
+    max_  = 0.0;
+    n_    = 0;
+    mean_ = 0.0;
+    S_    = 0.0;
+}
+
+FixTime ttf ("TTF" );           // Time to fix
+FixTime ttff("TTFF");           // Time to first fix
+
+void
+FixTime::fix_time(float t)
+{
+    ++n_;
+
+    // printf("%s += %.1f %d\n", name_, t, n_);
+
+    double delta = t - mean_;
+    mean_ += delta / (double) n_;
+    S_    += delta * (t - mean_);
+
+    if (t < min_) min_ = t;
+    if (t > max_) max_ = t;
+}
+
+char*
+FixTime::report(int n, char* buf) const
+{
+    if (n_ < 1)
+    {
+        sprintf(buf,    "%s(%d)   Min: - s    Max: - s\n"
+                        "Average: -        std -    ",
+            name_, n_);
+    }
+    else
+    {
+        sprintf(buf,    "%s(%d)   Min: %.1f s    Max: %.1f s\n"
+                        "Average: %.1f s     std %.1f",
+            name_, n_,
+            min_, max_, mean_, sqrt(S_/n_));
+    }
+    return buf;
+}
+
+void
+page_stats_fix_time(float TTF, float TTFF)
+{
+    if (TTFF > 0.0)
+    {
+        ttff.fix_time(TTFF);
+        page_stats_fix_time_update(MASK_TTFF);
+    }
+    else if (TTF > 0.0)
+    {
+        ttf.fix_time(TTF);
+        page_stats_fix_time_update(MASK_TTF);
+    }
+}
+
+void
+page_stats_init()
+{
+    ttf.init();
+    ttff.init();
+    page_stats_fix_time_update(MASK_TTFF | MASK_TTF);
+}
+
+static void
+page_stats_fix_time_report(FILE* f)
+{
+    char buf_ttf [128];
+    char buf_ttff[128];
+
+    fprintf(f, "Position Fix Time\n%s\n%s\n",
+                ttf.report (sizeof(buf_ttf ), buf_ttf ),
+                ttff.report(sizeof(buf_ttff), buf_ttff) );
+}
+
+void
+page_stats_report(FILE* f)
+{
+    // report the average position, CEP, etc.
+    page_stats_fix_time_report(f);
+}
+
+static void
+page_stats_fix_time_update(int x)
+{
+    char buf[128];
+
+    if (MASK_TTF & x)
+    {
+        ttf.report(sizeof(buf), buf);
+        gtk_label_set_text(wid_ttf, buf);
+    }
+
+    if (MASK_TTFF & x)
+    {
+        ttff.report(sizeof(buf), buf);
+        gtk_label_set_text(wid_ttff, buf);
+    }
+}
+
+void page_stats_done()
+{
+    // page_stats_position_update();
+    // page_stats_position_least_squares_update();
+    page_stats_fix_time_update(MASK_TTFF | MASK_TTF);
+}
+
+static gboolean
+expose_stats_event(GtkWidget* w, GdkEventExpose* event)
+{
+    notebook_expose("ST");
+    return FALSE;
+}
+
+
+GtkWidget*
+page_stats_create(GtkWidget* window)
+{
+    GtkWidget* label;
+    GtkWidget* button;
+    GtkWidget* w;
+    GtkWidget* vbox;
+    GtkWidget* table;
+
+    //--------------------------------------------------------------------------
+    //          table
+    //--------------------------------------------------------------------------
+    table = gtk_table_new(14, 2, TRUE);
+    gtk_signal_connect(GTK_OBJECT(table), "expose_event",
+                    G_CALLBACK(expose_stats_event), w);
+
+    //--------------------------------------------------------------------------
+    //          Position Average
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("Position Average");
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 0, 1);
+    gtk_widget_show(label);
+
+        //----------------------------------------------------------------------
+        //          Position Average : Lat..StdDev
+        //----------------------------------------------------------------------
+        label = gtk_label_new("Lat:   37.123456 N");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 1, 1, 2);
+        gtk_widget_show(label);
+        label = gtk_label_new("StdDev: 0.0 m ");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 1, 2, 1, 2);
+        gtk_widget_show(label);
+
+        //----------------------------------------------------------------------
+        //          Position Average : Lon..StdDev
+        //----------------------------------------------------------------------
+        label = gtk_label_new("Lon:  121.654321 W");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 1, 2, 3);
+        gtk_widget_show(label);
+        label = gtk_label_new("StdDev: 0.0 m ");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 1, 2, 2, 3);
+        gtk_widget_show(label);
+
+        //----------------------------------------------------------------------
+        //          Position Average : Alt..StdDev
+        //----------------------------------------------------------------------
+        label = gtk_label_new("Alt:  123 m");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 1, 3, 4);
+        gtk_widget_show(label);
+        label = gtk_label_new("StdDev: 0.0 m ");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 1, 2, 3, 4);
+        gtk_widget_show(label);
+
+    //--------------------------------------------------------------------------
+    //          Least Squares Average
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("Least Squares Average");
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 4, 5);
+    gtk_widget_show(label);
+
+        //----------------------------------------------------------------------
+        //          Least Squares Average : Lat..StdDev
+        //----------------------------------------------------------------------
+        label = gtk_label_new("Lat:   37.123456 N");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 1, 5, 6);
+        gtk_widget_show(label);
+        label = gtk_label_new("StdDev: 0.0 m ");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 1, 2, 5, 6);
+        gtk_widget_show(label);
+
+        //----------------------------------------------------------------------
+        //          Least Squares Average : Lon..StdDev
+        //----------------------------------------------------------------------
+        label = gtk_label_new("Lon:  121.654321 W");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 1, 6, 7);
+        gtk_widget_show(label);
+        label = gtk_label_new("StdDev: 0.0 m ");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 1, 2, 6, 7);
+        gtk_widget_show(label);
+
+        //----------------------------------------------------------------------
+        //          Least Squares Average : Alt..StdDev
+        //----------------------------------------------------------------------
+        label = gtk_label_new("Alt:  123 m");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 1, 7, 8);
+        gtk_widget_show(label);
+        label = gtk_label_new("StdDev: 0.0 m ");
+        gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+        gtk_table_attach_defaults(GTK_TABLE (table), label, 1, 2, 7, 8);
+        gtk_widget_show(label);
+
+    //--------------------------------------------------------------------------
+    //          Position Fix Time
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("Position Fix Time");
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 9, 10);
+    gtk_widget_show(label);
+
+    //----------------------------------------------------------------------
+    //          Position Fix Time : TTF
+    //----------------------------------------------------------------------
+    label = gtk_label_new("");
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 10, 12);
+    gtk_widget_show(label);
+    wid_ttf = GTK_LABEL(label);
+
+    //----------------------------------------------------------------------
+    //          Position Fix Time : TTFF
+    //----------------------------------------------------------------------
+    label = gtk_label_new("");
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE (table), label, 0, 2, 12, 14);
+    gtk_widget_show(label);
+    wid_ttff = GTK_LABEL(label);
+
+    page_stats_init();
+
+    gtk_widget_show(table);
+    return table;
+}

Added: developers/olv/openmoko-agpsui2/src/page_stress.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_stress.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_stress.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,329 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef  PAGE_STRESS_H__                // {
+#include "page_stress.h"
+#endif                                  // }
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#ifdef PAGE_STRESS
+
+extern void create_range_controls(GtkWidget* window, GtkWidget* vbox, bool test);
+extern const char* gllin_detect(void);
+extern const char* gllin_start(void);
+extern const char* gllin_stop(void);
+extern void stress_cb_start(GtkWidget* label);
+extern void clearStats();
+extern void notebook_expose(const char* pageName);
+extern bool doing_reset_gps;
+
+extern void page_pm_batch_next();
+extern void page_pm_fix_done();
+extern void page_pm_batch_done();
+
+GtkLabel* stressLabel;
+extern void NMEA_MSG(const char* msg);
+
+static gboolean
+expose_stress_event(GtkWidget* w, GdkEventExpose* event)
+{
+    notebook_expose("RR");
+    return FALSE;
+}
+
+static bool stress_test = false;
+extern void page_main_gllin(bool start);
+
+bool
+page_stress_on(void)
+{
+    return stress_test;
+}
+
+void
+page_stress_msg(const char* msg)
+{
+    gtk_label_set_text(stressLabel, msg);
+}
+
+void page_stress_done(void)
+{
+}
+
+static void
+on_clicked_reset_gps(GtkWidget* w, gpointer d)
+{
+    page_stress_msg("Resetting GPS ...");
+    gllin_stop();
+    doing_reset_gps = true;
+    gllin_start();
+    doing_reset_gps = false;
+    sleep(1);
+    gllin_stop();
+    page_stress_msg("GPS device reset is completed.");
+    page_pm_batch_done();
+}
+
+void
+page_stress_msg_int(const char* msg, int n)
+{
+    char buf[88];
+    sprintf(buf, "%s %d", msg, n);
+    page_stress_msg(msg);
+}
+
+int
+stress_rand(int min, int max)
+{
+    int result = min + rand() % (max-min);
+    printf("stress_rand(%d,%d) %d\n", min, max, result);
+    return result;
+}
+
+guint stress_timeout_id = 0;
+static guint on_timeout_stress(GtkWidget* w, gpointer d);
+
+// Caution:  called from a timer thread, so all called GTK+ widgets
+//      must be protected by gdk_threads_enter() and gdk_threads_leave()
+
+static void
+stress_stop()
+{
+    stress_timeout_id = 0;
+    // gdk_threads_remove_timeout(stress_timeout_id);
+
+    gllin_stop();
+    page_stress_msg("Stopping");
+}
+
+//------------------------------------------------------------------------------------
+//
+//              Report
+//
+//  page_stress_do_report() - generate a report
+//  page_stress_set_report_name() - update the report label on the button.
+//  on_clicked_report() - start the generation of a report.
+//
+//------------------------------------------------------------------------------------
+
+void notebook_report(FILE* f);
+
+static int report_id = 0;
+extern const char* page_main_test_name(void);
+
+bool
+page_stress_do_report(void)
+{
+    const char* test_name = page_main_test_name();
+    if (!test_name) return false;
+
+    char report_name[32];
+    sprintf(report_name, "./log/%s-R-%d.txt", test_name, report_id);
+
+    FILE* f = fopen(report_name, "a+");
+    if (!f)
+    {
+        fprintf(stderr, "omgui: can't create report file %s:  %d %s\n",
+                                        report_name, errno, strerror(errno));
+        return false;
+    }
+    notebook_report(f);
+    fclose(f);
+    ++report_id;
+    return true;
+}
+
+static GtkButton* wid_report = 0;
+
+void
+page_stress_set_report_name(void)
+{
+    if (wid_report)
+    {
+        char report_name[32];
+        sprintf(report_name, "Report %s-R-%d", page_main_test_name(), report_id);
+        gtk_button_set_label(wid_report, report_name);
+    }
+}
+
+static void
+on_clicked_report(GtkWidget* w, gpointer d)
+{
+    if (page_main_test_name())
+    {
+        page_stress_do_report();
+        page_stress_set_report_name();
+    }
+}
+
+// Caution:  MIGHT be called from a timer thread, so all called GTK+ widgets
+//      must be protected by gdk_threads_enter() and gdk_threads_leave()
+
+#ifdef OPT_STRESS_FEATURE                       // {
+
+static void
+stress_start(void)
+{
+    page_main_gllin(true);
+    int timeout = stress_rand(2,600);      // run time is 2..600 seconds.
+    stress_timeout_id = g_timeout_add_seconds(timeout, (gboolean (*)(void*))on_timeout_stress, 0);
+    page_stress_msg_int("Started stress test", timeout);
+}
+
+static guint
+on_timeout_stress(GtkWidget* w, gpointer d)
+{
+    if (!stress_timeout_id) return FALSE;
+    stress_stop();
+
+    int timeout = stress_rand(0,30);     // Sleep between 0 and 30 seconds;
+    page_stress_msg_int("Stress delay", timeout);
+    sleep(timeout);
+
+    stress_start();
+    return FALSE;
+}
+
+static void
+on_clicked_stress(GtkWidget* w, gpointer d)
+{
+    stress_test = !stress_test;
+    if (stress_test)
+    {
+        stress_start();
+    }
+    else
+    {
+        stress_stop();
+    }
+}
+#endif
+
+void
+page_stress_RID()
+{
+    page_pm_batch_next();
+}
+
+void
+page_stress_FIX()
+{
+    page_pm_fix_done();
+}
+
+void
+page_stress_EXIT()
+{
+    // page_main_gllin(false);                  // don't have this yet.
+    page_pm_batch_done();
+    gllin_stop();
+}
+
+GtkWidget*
+page_stress_create(GtkWidget* window)
+{
+    GtkWidget* label;
+    GtkWidget* button;
+    GtkWidget* vbox;
+    GtkWidget* table;
+
+    //--------------------------------------------------------------------------
+    //          table
+    //--------------------------------------------------------------------------
+    table = gtk_table_new(14, 2, TRUE);
+    gtk_signal_connect(GTK_OBJECT(table), "expose_event",
+                    G_CALLBACK(expose_stress_event), table);
+
+    //--------------------------------------------------------------------------
+    //          label
+    //
+    //  All text from the "stress" page goes to this stressLabel
+    //--------------------------------------------------------------------------
+    label = gtk_label_new("Future panel to show stress test results");
+    stressLabel = GTK_LABEL(label);
+    gtk_label_set_justify(stressLabel, GTK_JUSTIFY_LEFT);
+    gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 1, 8);
+    gtk_widget_show(label);
+
+#ifdef OPT_STRESS_FEATURE
+    //--------------------------------------------------------------------------
+    //          start stress test button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("Start Stress Test");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_stress), label);
+    gtk_table_attach_defaults(GTK_TABLE (table), button, 0, 2, 8, 9);
+    gtk_widget_show(button);
+#endif
+
+    //--------------------------------------------------------------------------
+    //          range controls
+    //--------------------------------------------------------------------------
+    create_range_controls(window, table, true);
+
+    //--------------------------------------------------------------------------
+    //          reset GPS button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("Reset GPS");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                     G_CALLBACK(on_clicked_reset_gps), label);
+    gtk_table_attach_defaults(GTK_TABLE (table), button, 0, 1, 13, 14);
+    gtk_widget_show(button);
+
+    //--------------------------------------------------------------------------
+    //          report button
+    //--------------------------------------------------------------------------
+    button = gtk_button_new_with_label("Report");
+    g_signal_connect(G_OBJECT(button), "clicked",
+                    G_CALLBACK(on_clicked_report), NULL);
+    gtk_table_attach_defaults(GTK_TABLE (table), button, 1, 2, 13, 14);
+    gtk_widget_show(button);
+    wid_report = GTK_BUTTON(button);
+
+    gtk_widget_show(table);
+    return table;
+}
+
+#else                   // } {
+
+void page_stress_msg(const char* msg)
+{
+}
+
+void page_stress_done(void)
+{
+}
+
+#endif                  // }
+
+
+extern void pm_report(FILE* f, bool stress);
+
+void
+page_stress_report(FILE* f)
+{
+    pm_report(f, true);
+}

Added: developers/olv/openmoko-agpsui2/src/page_stress.h
===================================================================
--- developers/olv/openmoko-agpsui2/src/page_stress.h	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/page_stress.h	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef  PAGE_STRESS_H__                // {
+#define  PAGE_STRESS_H__
+
+#ifndef  PAGE_STRESS_H__                // {
+#include "page_stress.h"
+#endif                                  // }
+
+#ifndef  __GLIB_H__                // {
+#include <glib.h>
+#endif                             // }
+
+#define PAGE_STRESS
+// #undef  PAGE_STRESS
+
+//      Unfortunately, the stress test requires
+//      the g_timeout_add_seconds() api which is
+//      present in GTK+ v2.14 and later only....
+
+#if (    ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION >= 14)) \
+      ||  (GLIB_MAJOR_VERSION >  2)   )
+#else
+#undef  OPT_STRESS_FEATURE
+#endif
+
+#endif                  // }

Added: developers/olv/openmoko-agpsui2/src/pm_agps.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/pm_agps.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/pm_agps.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,724 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include "nmea.h"
+
+#include <gtk/gtk.h>
+#include <glib/gprintf.h>
+
+int gllin_fd();
+extern void page_MAP_have_lla(double lon, double lat, int alt, int heading, int speed, int time);
+extern FILE *dump_nmea_fp;
+extern int debug_all;
+
+void page_log_append(const char *nmea);
+
+#define FIFO "/tmp/nmeaNP"
+#define NV1  "./NVRAM1.DAT"
+#define NV2  "./NVRAM2.DAT"
+#define LLL  "log"
+
+#undef SLOG
+
+#ifdef SLOG
+#define LOG  "/dev/log"
+#endif
+
+#define SIZE 128
+#define GOT  3
+
+FILE* fp1 = NULL;
+int finish = 0;
+char* gllin_stop(void);
+gint agps_cb_nmea_tag = 0;
+static void agps_nmea_process(GtkWidget* label, unsigned char* buf, int size);
+unsigned long int runtime();
+extern void page_SS_init();
+extern void page_RFI_handle_GSV(nmea_gsv* pGSV);
+extern void page_RFI_handle_GGA(nmea_gga* pGGA);
+extern void pm_controls_nmea_epoch_done(void);
+extern void page_stress_RID();
+extern void page_stress_FIX();
+extern void page_stress_EXIT();
+
+//static char buffer_zone[1024];          // Somebody is overwriting a buffer.
+static struct nmea_gga n_gga;
+static struct nmea_rmc n_rmc;
+static struct nmea_gsv n_gsv[GOT];
+static struct nmea_gsa n_gsa;
+static struct nmea_lor n_lor;
+
+GtkLabel* agpsLabel = 0;
+
+void NMEA_MSG(const char* msg)
+{
+    if (agpsLabel)
+    {
+        gtk_label_set_text(agpsLabel, msg);		
+    }
+}
+
+static void NMEA_DEBUG(const char* msg)
+{
+#if 0
+#ifdef DEBUG_LV1			
+    printf("%s\n", msg);		
+#endif				
+#ifdef DEBUG_LV3
+    NMEA_MSG(msg);
+#endif	
+#ifdef DEBUG_LV5
+    print(msg);
+#endif
+#ifdef SLOG			
+    if (fp1) fputs(msg, fp1);
+#endif			
+#endif
+}
+
+gboolean stop(GtkWidget *widget)
+{
+    finish = 1;
+    return FALSE;
+}
+
+void
+agps_fd(gpointer data, gint source, GdkInputCondition cond)
+{
+    //  For stress test only:
+    //  Only needed if the g_timeout_cb() is not thread-safe:
+    //
+    //          page_main_poll_for_stop();
+    //
+
+    GtkWidget* label = GTK_WIDGET(data);
+    if (source != gllin_fd())
+    {
+        NMEA_DEBUG("fd mismatch");
+        return;
+    }
+    if (GDK_INPUT_READ != cond)
+    {
+        NMEA_DEBUG("gtk read callback condition mismatch");
+        return;
+    }
+    unsigned char buf[SIZE+1];
+    int n = read(source, buf, SIZE);
+    if (n > 0)
+	    agps_nmea_process(label, buf, n);
+    else
+	    printf("read failed\n");
+}
+
+void
+agps_cb_start(GtkWidget* label)
+{
+    agps_cb_nmea_tag = gdk_input_add(gllin_fd(), GDK_INPUT_READ, agps_fd, label);
+}
+
+void
+agps_cb_stop()
+{
+    gdk_input_remove(agps_cb_nmea_tag);
+}
+
+int fix_good  = 0;
+int fix_fail  = 0;
+int fix_total = 0;
+static int ttff;
+
+extern void page_MAP_init(void);
+
+void
+clearStats()
+{
+    fix_good  = 0;
+    fix_fail  = 0;
+    fix_total = 0;
+    ttff = 0;
+    page_SS_init();
+    page_MAP_init();
+}
+
+static char line_buffer[1024] = { 0 };
+static void agps_nmea_process_(GtkWidget* label, char* buf);
+
+//-------------------------------------------------------------------------------------
+//
+//      agps_nmea_process()
+//
+//      Convert the chunks of NMEA data into separate sentences.
+//      Then process.
+//
+//-------------------------------------------------------------------------------------
+
+static unsigned int next_msg(GByteArray **pq)
+{
+	unsigned char *head, *tail, *end;
+	GByteArray *q = *pq;
+
+	if (q->len < 5)
+		return FALSE;
+
+	end = q->data + q->len;
+
+	head = q->data;
+	tail = end + 1;
+
+	while (head < end)
+	{
+		if (*head == 0xb5)
+		{
+			if (head + 6 > end)
+				break;
+
+			if (head[1] == 0x62)
+			{
+				int len;
+
+				len = head[4] | (head[5] << 8);
+				/* limit payload size */
+				if (len < 0x100)
+				{
+					tail = head + 6 + len + 2;
+
+					//printf("ubx of len %d, got %d\n", len, q->len);
+
+					break;
+				}
+			}
+		}
+		else if (*head == '$')
+		{
+			unsigned char *tmp = head + 1;
+
+			while (g_ascii_isprint(*tmp) && tmp < end)
+				tmp++;
+
+			if (tmp + 2 > end)
+				break;
+
+			if ((tmp[0] == '\r' || tmp[0] == '\n') && tmp[1] == '\n')
+			{
+				tail = tmp + 2;
+
+				break;
+			}
+			else
+			{
+				printf("nmea ends with 0x%02x 0x%02x\n", tmp[0], tmp[1]);
+				head = tmp - 1;
+			}
+		}
+
+		head++;
+	}
+
+	if (q->data < head)
+	{
+
+#if 0
+		if (head - q->data == 20 && q->data[0] == 0x10 && q->data[1] == 0x00)
+		{
+			unsigned char nav_status[] = { 0xb5, 0x62, 0x01, 0x03 };
+
+			q = g_byte_array_prepend(q, nav_status, sizeof(nav_status));
+
+			head = q->data;
+			tail = q->data + 24;
+			end = q->data + q->len;
+		}
+		else
+#endif
+		{
+			if (debug_all)
+			{
+				int i;
+
+				printf("abandoning %d bytes of %d bytes\n---\n", head - q->data, q->len);
+
+				for (i = 0; i < head - q->data; i++)
+				{
+					printf("0x%02x", q->data[i]);
+					printf("%c", (i % 16 == 15) ? '\n' : ' ');
+				}
+				printf("\n---\n");
+			}
+
+			q = g_byte_array_remove_range(q, 0, head - q->data);
+		}
+
+		*pq = q;
+	}
+
+	return (tail <= end) ? (tail - head) : 0;
+}
+
+#define READ32(p)	(READ16(p) | READ16((p) + 2) << 16)
+#define READ16(p)	((p)[0] | (p)[1] << 8)
+#define READ8(p)	((p)[0])
+
+static void ubx_process(unsigned char *buf, size_t size)
+{
+	unsigned char *p, cls, id, checksum[2];
+	unsigned int i, payload;
+
+	if (size < 6 || buf[0] != 0xb5 || buf[1] != 0x62)
+	{
+		printf("invalid ubx\n");
+
+		return;
+	}
+
+	cls = buf[2];
+	id = buf[3];
+
+	payload = READ16(buf + 4);
+	if (6 + payload + 2 != size)
+	{
+		printf("wrong ubx size\n");
+
+		return;
+	}
+
+	checksum[0] = checksum[1] = 0;
+	for (i = 2; i < size - 2; i++)
+	{
+		checksum[0] += buf[i];
+		checksum[1] += checksum[0];
+	}
+
+	if (buf[size - 2] != checksum[0] || buf[size - 1] != checksum[1])
+	{
+		printf("wrong checksum (should be 0x%02x%02x, not 0x%02x%02x)\n",
+				checksum[0], checksum[1],
+				buf[size - 2], buf[size - 1]);
+
+		return;
+	}
+
+	p = &buf[6];
+
+	printf("received (0x%02x 0x%02x)\n", cls, id);
+
+	switch (cls)
+	{
+	case 0x05:
+		if (id == 0x01)
+			printf("(0x%02x 0x%02x) acked\n", p[0], p[1]);
+		break;
+	case 0x01:
+		switch (id)
+		{
+		case 0x03:
+			printf("STATUS %u 0x%x 0x%x 0x%x %u %u\n",
+					READ32(p) / 1000, READ8(p + 4), READ8(p + 5),
+					READ8(p + 6), READ32(p + 8), READ32(p + 12));
+			break;
+		case 0x22:
+			printf("TIME %u %d %d %u %u\n",
+					READ32(p) / 1000, READ32(p + 4), READ32(p + 8),
+					READ32(p + 12), READ32(p + 16));
+			break;
+		}
+		break;
+	}
+}
+
+static void
+agps_nmea_process(GtkWidget* label, unsigned char* buf, int size)
+{
+    static GByteArray *q;
+    int s;
+
+    if (!q)
+    {
+	    q = g_byte_array_new();
+	    if (!q)
+		    return;
+    }
+
+    q = g_byte_array_append(q, buf, size);
+
+    while ((s = next_msg(&q)))
+    {
+	    if (q->data[0] == '$')
+	    {
+		    memcpy(line_buffer, q->data, s - 2);
+		    line_buffer[s - 2] = '\0';
+
+		    agps_nmea_process_(label, line_buffer);
+	    }
+	    else
+		    ubx_process(q->data, s);
+
+	    q = g_byte_array_remove_range(q, 0, s);
+    }
+}
+
+//------------------------------------------------------------------------------
+//
+//               nmea_to_ll(const char* s, float& lat)
+//
+//      Convert 12345.678 into
+//      123 degrees, 45.678 minutes, or
+//      123.761300 degrees.
+//
+//------------------------------------------------------------------------------
+
+static float
+nmea_to_ll(const char* s)
+{
+    bool  negate = false;
+    if (*s == '-')
+    {
+        negate = true;
+        ++s;
+    }
+
+    float fll;
+    sscanf(s, "%f", &fll);              // 12345.678
+
+    int   ill;
+    sscanf(s, "%d", &ill);              // 12345
+    float degrees = ill / 100;          // 123.0
+
+    fll -= degrees * 100;               // 12345.678 - 12300.0 = 45.678
+    degrees += fll/60.0;                // 123.0 + 45.678/60.0 = 123.7613
+    if (negate)
+    {
+        degrees = -degrees;
+    }
+    return degrees;
+}
+
+extern char testStartTime[];
+
+static char nmea_epoch_string[2048] = {0};
+
+const char*
+nmea_epoch()
+{
+    return nmea_epoch_string;
+}
+
+static void
+nmea_epoch_end(struct nmea_gga* gga, struct nmea_lor* lor)
+{
+    char tmp[1024];
+    char* p = tmp;
+    memset(tmp, 0, sizeof(tmp));
+
+    //p += sprintf(p, "Start time: %s\n", testStartTime);
+
+    // TODO:  Report more info
+    //        Be smarter about calling this procedure
+    //        Save the data so we can press a "report" button to save to file.
+    {
+        unsigned long total_sec = runtime();
+        p += sprintf(p, "Module Uptime:");
+
+        if (total_sec > 59)
+        {
+            int hours =  total_sec / 3600;
+            int min   = (total_sec % 3600) / 60;
+            int sec   = (total_sec %   60);
+
+            p += sprintf(p, " %02d:%02d:%02d", hours, min, sec);
+
+        }
+        p += sprintf(p, " (%d s)\n", (int) total_sec);
+    }
+
+    if (fix_total)
+    {
+        p += sprintf(p, "Fixes: %d good  %d fail   %d total\n",
+                         fix_good, fix_fail, fix_total);
+    }
+    else
+    {
+        p += sprintf(p, "Starting\n");
+    }
+
+    if (ttff)
+    {
+	    p += sprintf(p, "TTFF: %ds\n", ttff);
+    }
+    else
+    {
+	    p += sprintf(p, "TTFF: -\n");
+    }
+
+    if (gga->time[0])
+    {
+        char fixTime[32];
+
+        fixTime[0] = gga->time[0];
+        fixTime[1] = gga->time[1];
+        fixTime[2] = ':';
+        fixTime[3] = gga->time[2];
+        fixTime[4] = gga->time[3];
+        fixTime[5] = ':';
+        fixTime[6] = gga->time[4];
+        fixTime[7] = gga->time[5];
+        fixTime[8] = gga->time[6];
+        fixTime[9] = gga->time[7];
+        fixTime[10] = gga->time[8];
+        fixTime[11] = 0;
+        p += sprintf(p, "UTC: %s\n", fixTime);
+    }
+    else
+    {
+        p += sprintf(p, "Fix time: -\n");
+    }
+
+    if (strlen(gga->latitude) && strlen(gga->longitude))
+    {
+        float lat = nmea_to_ll(gga->latitude);
+        float lon = nmea_to_ll(gga->longitude);
+
+        int alt;
+        sscanf(gga->alme, "%d", &alt);
+
+        const char* alt_units = "m";
+
+        p += sprintf(p,
+                     "Latitude:  %10.6f %s\n"
+                     "Longitude: %10.6f %s\n"
+                     "Altitude:  %d %s\n"
+                     "HDOP:      %s\n",
+             lat, gga->la,
+             lon, gga->lo,
+             alt, alt_units,
+             gga->hdop);
+
+        if (strchr(gga->la, 'S'))
+        {
+            lat = -lat;
+        }
+
+        if (strchr(gga->lo, 'W'))
+        {
+            lon = -lon;
+        }
+
+        // TODO:  fill in alt, speed, and heading
+
+        page_MAP_have_lla(lon, lat, 50, 0, 0, 123000);
+    }
+    else
+    {
+        p += sprintf(p,
+                     "Latitude:  -\n"
+                     "Longitude: -\n"
+                     "Altitude:  -\n"
+                     "HDOP:      -\n");
+    }
+
+    if (gga->nos[0])
+    {
+        int nsat;
+        sscanf(gga->nos,  "%d", &nsat);
+        p += sprintf(p, "Num sats: %d\n", nsat);
+    }
+    else
+    {
+        p += sprintf(p, "\n");
+    }
+
+    if (lor->rid[0])
+    {
+        p += sprintf(p, "Version: %s\n", lor->rid);
+    }
+    if (lor->nIgr)
+    {
+        p += sprintf(p, "IGR: %d) %s", lor->nIgr, lor->igr);
+    }
+    // g_printf("%s", tmp);
+    NMEA_MSG(tmp);
+
+    strcpy(nmea_epoch_string, tmp);
+
+    pm_controls_nmea_epoch_done();
+}
+
+//-------------------------------------------------------------------------------------
+//
+//      agps_nmea_process_()
+//
+//      Process the NMEA sentences.
+//
+//-------------------------------------------------------------------------------------
+
+static void
+agps_nmea_process_(GtkWidget* label, char* buf)
+{
+    int j = 0;
+
+    struct nmea_gga* gga = &n_gga;
+    struct nmea_rmc* rmc = &n_rmc;
+    struct nmea_gsv* gsv =  n_gsv;
+    struct nmea_gsa* gsa = &n_gsa;
+    struct nmea_lor* lor = &n_lor;
+
+    NMEA_DEBUG(buf);
+
+    page_log_append(buf);
+    if (dump_nmea_fp)
+	    g_fprintf(dump_nmea_fp, ">%s\n", buf);
+
+    if (strstr(buf,GGA))
+    {
+        memset(gga, 0, sizeof(struct nmea_gga));
+        NMEA_DEBUG("$GPGGA");
+        GPGGA(buf, gga);						
+        //page_RFI_handle_GGA(gga);
+
+#ifdef DEBUG_LV2
+        printf("Sentence: %s\n", gga->sentence);
+        printf("FIX Taken: %s\n", gga->time);
+        printf("Latitude: %s\n", gga->latitude);
+        printf("%s\n", gga->la);
+        printf("Longitude: %s\n", gga->longitude);
+        printf("%s\n", gga->lo);
+        printf("Fix quality: %s\n", gga->fix_quality);
+        printf("Num of sat: %s\n", gga->nos);
+        printf("Horizontal dilution: %s\n", gga->hdop);
+        printf("Altitude: %s\n", gga->alme);
+        printf("%s\n", gga->al);
+        printf("Height of geoid: %s\n", gga->hog);
+        printf("%s\n", gga->ho);
+        printf("time in seconds: %s\n", gga->tis);
+        printf("DGPS ID: %s\n", gga->DGPS);
+        printf("checksum: %s\n", gga->checksum);
+#endif
+    }
+    else if (strstr(buf,RMC))
+    {
+        memset(rmc, 0, sizeof(struct nmea_rmc));
+        NMEA_DEBUG("$GPRMC");
+        if (strstr(buf, ",A,"))
+        {
+            ++fix_good;
+	    if (fix_good > 2 && !ttff)
+		    ttff = runtime();
+        }
+        else
+        {
+            ++fix_fail;
+        }
+        ++fix_total;
+
+        GPRMC(buf, rmc);	
+        // g_printf("RMC: (%d+%d)/%d\n", fix_good, fix_fail, fix_total);
+    }
+    else if (strstr(buf,GSA))
+    {
+        memset(gsa, 0, sizeof(struct nmea_gsa));
+        NMEA_DEBUG("$GPGSA");
+        GPGSA(buf, gsa);
+#ifdef DEBUG_LV2
+        printf("Sentence: %s\n", gsa->sentence);
+        printf("Auto/Manual: %s\n", gsa->AM);
+        printf("mode: %s\n", gsa->mode);
+
+        for (i = 0; i < 12; ++i) 
+        {
+            printf("PRN(%d): %s\n", i, gsa->id[i]);
+        }
+
+        printf("PDOP: %s\n", gsa->PDOP);
+        printf("HDOP: %s\n", gsa->HDOP);
+        printf("VDOP: %s\n", gsa->VDOP);
+        printf("checksum: %s\n", gsa->checksum);
+        printf("Num of Sate: %d\n",gsa->n);
+#endif
+        nmea_epoch_end(gga, lor);
+    }
+    else if (strstr(buf,GSV))
+    {
+        nmea_gsv* pGSV = gsv+j;
+        memset(pGSV, 0, sizeof(struct nmea_gsv));
+        NMEA_DEBUG("$GPGSV");
+        GPGSV(buf, pGSV);	
+#ifdef DEBUG_LV6
+        printf("Sentence: %s\n",        pGSV->sentence);
+        printf("Num of sentence: %s\n", pGSV->nose);
+        printf("sentence #: %s\n",      pGSV->sn);
+        printf("Num of sate: %s\n",     pGSV->nosa);
+
+        for (i = 0; i < pGSV->n; ++i)
+        {
+            printf("(%d) PRN: %s\n",       i, pGSV->sate[i][0]); printf("(%d) Elevation: %s\n", i, pGSV->sate[i][1]);
+            printf("(%d) Azimuth: %s\n",   i, pGSV->sate[i][2]);
+            printf("(%d) SNR: %s\n",       i, pGSV->sate[i][3]);
+        }
+
+        printf("checksum: %s\n", (gsv+j)->checksum);
+#endif
+
+        //page_RFI_handle_GSV(pGSV);
+        ++j;
+    }
+    else if (strstr(buf,"PGLOR,RID"))
+    {
+        memset(lor, 0, sizeof(struct nmea_lor));
+        PGLOR_RID(buf, lor);
+        page_stress_RID();
+    }
+    else if (strstr(buf,"PGLOR,IG"))
+    {
+        PGLOR_IGR(buf, lor);
+    }
+    else if (strstr(buf,"PGLOR,FIX"))
+    {
+        PGLOR_FIX(buf, lor);
+        // nmea_epoch_end(gga, lor);
+        page_stress_FIX();
+    }
+    else if (strstr(buf,"PGLOR,EXIT"))
+    {
+        PGLOR_EXIT(buf, lor);
+        // nmea_epoch_end(gga, lor);
+        page_stress_EXIT();
+    }
+}
+
+void agps_stop(void)
+{
+    finish = TRUE;	
+}
+
+
+#if 0
+
+
+
+#endif

Added: developers/olv/openmoko-agpsui2/src/pm_controls.cpp
===================================================================
--- developers/olv/openmoko-agpsui2/src/pm_controls.cpp	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/pm_controls.cpp	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,777 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gtk/gtk.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+const char* start_type = "hot";
+bool allow_lto = true;
+extern bool doing_ptf;
+
+bool doing_stress = false;
+int  stress_count = -1;
+
+static bool set_timeout = false;
+static bool set_accuracy_mask = false;
+static int  accuracy_mask = 50;
+static int  timeout = 64;
+static GtkWidget* wid_box_accuracy_mask;
+static GtkWidget* wid_box_timeout;
+static GtkAdjustment* wid_batch_adj;
+static GtkAdjustment* wid_fix_adj;
+
+//------------------------------------------------------------------------------
+//
+//      Range/Scale Widgets for OMGUI
+//
+//  Ken Yale
+//  Global Locate
+//
+//  Ranges:
+//      Fix Period 0...64, where 0 is native.
+//      Fix Type:  HOT (default), WARM, COLD, SNR
+//                 Fix type has option for LTO on or off.
+//      Batch count 1..1000  [only if the "do batches" is active]
+//      Fix   count 1..1000  [only if the "do batches" is active]
+//
+//  Special Cases:
+//      If Batch count is 0, then do a OMGUI stress test (forever).
+//      Start the GLLIN, then wait fix_count fixes (good or bad), then
+//      stop the GLLIN, sleep 1 second & repeat forever.
+//      In this case, if fix_count is 0, then the fix_count is computed
+//      to be a random number between 10 and 265 (inclusive).
+//
+//  Buttons:
+//      Do batches or not.
+//      simulator used or not.
+//      sensitivity/driving
+//      logging on/off
+//
+//  Behavior:
+//      fix period adjustment is shared between RUN and TEST pages.
+//      Simulator button is shared between RUN and TEST pages.
+//
+//      All controls are disabled (but visible) when the GLLIN is running.
+//
+//      All BATCH_COUNT and FIX_COUNT are invisble until BATCH is on.
+//
+//------------------------------------------------------------------------------
+
+static void cb_pos_menu_select( GtkWidget       *item,
+                                GtkPositionType  pos )
+{
+    allow_lto  = true;
+    start_type = (const char*) pos;
+
+    if (strstr(start_type, "(no LTO)"))
+    {
+        static char tmp_start[32];
+        strcpy(tmp_start, start_type);
+
+        char* p = strchr(tmp_start, '(');
+        p[-1] = 0;
+
+        allow_lto = false;
+        start_type = tmp_start;
+    }
+
+    printf("start type %s \"%s\"\n", start_type, (char*) pos);
+}
+
+int fix_rate = 0;
+
+GtkAdjustment* wid_fix_rate0 = 0;
+GtkAdjustment* wid_fix_rate1 = 0;
+
+static void cb_fix_rate(GtkAdjustment* adj)
+{
+    static bool locked = false;
+
+    if (!locked)
+    {
+        locked = true;
+        if (adj != wid_fix_rate0) gtk_adjustment_set_value(wid_fix_rate0, adj->value);
+        if (adj != wid_fix_rate1) gtk_adjustment_set_value(wid_fix_rate1, adj->value);
+        locked = false;
+
+        fix_rate = (gint) adj->value;
+        printf("fix rate %d\n", fix_rate);
+    }
+}
+
+static void
+cb_accuracy_mask(GtkAdjustment* adj)
+{
+    set_accuracy_mask = true;
+    accuracy_mask = (gint) adj->value;
+    // printf("accuracy_mask %d\n", accuracy_mask);
+}
+
+static void
+cb_timeout(GtkAdjustment* adj)
+{
+    set_timeout = true;
+    timeout = (gint) adj->value;
+    // printf("timeout %d\n", timeout);
+}
+
+int fix_count = 1;
+
+static void cb_fix_count( GtkAdjustment* adj)
+{
+    fix_count = (gint) adj->value;
+    // printf("fix count %d\n", fix_count);
+}
+
+int batch_count = 0;
+
+static void cb_batch_count( GtkAdjustment* adj)
+{
+    batch_count = (gint) adj->value;
+    // printf("batch count %d\n", batch_count);
+}
+
+GtkWidget* wid_batch_count;
+GtkWidget* wid_fix_count;
+
+bool doing_batch = false;
+bool doing_reset_gps = false;
+
+static void cb_batch_allowed(GtkToggleButton* button)
+{
+    printf("batch allowed %d\n", button->active);
+    if (button->active)
+    {
+        gtk_widget_show(wid_batch_count);
+        gtk_widget_show(wid_fix_count);
+        doing_batch = true;
+    }
+    else
+    {
+        gtk_widget_hide(wid_batch_count);
+        gtk_widget_hide(wid_fix_count);
+        doing_batch = false;
+    }
+}
+
+int nmea_log = TRUE;
+GtkToggleButton* wid_log0;
+GtkToggleButton* wid_log1;
+
+static void cb_nmea_log_value( GtkToggleButton* button)
+{
+    nmea_log = button->active;
+    printf("nmea_log %d\n", nmea_log);
+    if (button != wid_log0) gtk_toggle_button_set_active(wid_log0, nmea_log);
+    if (button != wid_log1) gtk_toggle_button_set_active(wid_log1, nmea_log);
+}
+
+int using_simulator = FALSE;
+
+static void cb_simulator_value( GtkToggleButton* button)
+{
+    using_simulator = button->active;
+    printf("simulator %d\n", using_simulator);
+}
+
+int pnd_mode = TRUE;
+GtkToggleButton* wid_pnd0;
+GtkToggleButton* wid_pnd1;
+
+static void cb_pnd_value( GtkToggleButton* button)
+{
+    pnd_mode = button->active;
+    printf("pnd_mode %d\n", pnd_mode);
+    if (button != wid_pnd0) gtk_toggle_button_set_active(wid_pnd0, pnd_mode);
+    if (button != wid_pnd1) gtk_toggle_button_set_active(wid_pnd1, pnd_mode);
+}
+
+/* Convenience functions */
+
+static GtkWidget* make_menu_item(gchar* name, GCallback callback)
+{
+    GtkWidget* item = gtk_menu_item_new_with_label (name);
+    g_signal_connect (G_OBJECT (item), "activate", callback, (gpointer)name);
+    gtk_widget_show (item);
+
+    return item;
+}
+
+void scale_init(GtkScale* scale)
+{
+    gtk_range_set_update_policy (GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS);
+    gtk_scale_set_digits     (scale, 0);
+    gtk_scale_set_value_pos  (scale, GTK_POS_RIGHT);
+    gtk_scale_set_draw_value (scale, TRUE);
+}
+
+static void cb_arrow_clicked(GtkButton* b, gpointer user_data)
+{
+    int offset = GPOINTER_TO_INT(user_data);
+    gdouble value = gtk_adjustment_get_value(wid_fix_rate0);
+    printf("arrow click offset %d + %f\n", offset, value);
+
+    value += offset;
+    gtk_adjustment_set_value(wid_fix_rate0, value);
+    gtk_adjustment_set_value(wid_fix_rate1, value);
+    // gtk_button_set_relief(b, GTK_RELIEF_NONE);
+}
+
+static GtkWidget* create_arrow_button(GtkArrowType a, int offset)
+{
+    GtkShadowType s = GTK_SHADOW_ETCHED_OUT;
+
+    GtkWidget* button = gtk_button_new();
+    GtkWidget* arrow  = gtk_arrow_new(a, s);
+    gtk_container_add(GTK_CONTAINER(button), arrow);
+    g_signal_connect (G_OBJECT (button), "clicked",
+                      G_CALLBACK (cb_arrow_clicked), GINT_TO_POINTER(offset));
+    gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+    gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);
+    gtk_widget_show(arrow);
+    gtk_widget_show(button);
+    return button;
+}
+
+GtkWidget* wid_batch_mode = 0;
+GtkWidget* wid_simulator  = 0;
+GtkWidget* box_fix_type   = 0;
+GtkWidget* wid_fix_box0   = 0;
+GtkWidget* wid_fix_box1   = 0;
+
+//      The gllin.cpp calls us
+
+void
+pm_controls_active(bool active)
+{
+    if (box_fix_type)  gtk_widget_set_sensitive(box_fix_type,      active);
+    if (wid_simulator) gtk_widget_set_sensitive(wid_simulator,     active);
+    if (wid_batch_mode)gtk_widget_set_sensitive(wid_batch_mode,    active);
+    if (wid_batch_count) gtk_widget_set_sensitive(wid_batch_count, active);
+    if (wid_fix_count) gtk_widget_set_sensitive(wid_fix_count,     active);
+    if (wid_log0)      gtk_widget_set_sensitive(GTK_WIDGET(wid_log0), active);
+    if (wid_log1)      gtk_widget_set_sensitive(GTK_WIDGET(wid_log1), active);
+    if (wid_pnd0)      gtk_widget_set_sensitive(GTK_WIDGET(wid_pnd0), active);
+    if (wid_pnd1)      gtk_widget_set_sensitive(GTK_WIDGET(wid_pnd1), active);
+    if (wid_fix_box0)  gtk_widget_set_sensitive(wid_fix_box0,    active);
+    if (wid_fix_box1)  gtk_widget_set_sensitive(wid_fix_box1,    active);
+    if (wid_box_accuracy_mask)  gtk_widget_set_sensitive(wid_box_accuracy_mask,    active);
+    if (wid_box_timeout)  gtk_widget_set_sensitive(wid_box_timeout,    active);
+}
+
+//-----------------------------------------------------------------------------------
+//
+//              Direct connection to the batch tests.
+//
+//      The NMEA is decoded and these functions are called when
+//      a batch test starts, and when a fix is done.
+//
+//-----------------------------------------------------------------------------------
+
+static int real_batch_count;
+static int real_fix_count;
+
+static void
+update_batch_count()
+{
+    gtk_adjustment_set_value(wid_batch_adj, batch_count);
+}
+
+static void
+update_fix_count()
+{
+    gtk_adjustment_set_value(wid_fix_adj, fix_count);
+}
+
+void
+page_pm_batch_start()
+{
+    if (!doing_batch) return;
+    real_batch_count = batch_count;
+    real_fix_count   = fix_count;
+    printf("page_pm_batch_start()/%d %d %d\n",
+                __LINE__, real_batch_count, real_fix_count);
+}
+
+void
+page_pm_batch_next()
+{
+    if (!doing_batch) return;
+    fix_count = real_fix_count;
+    --batch_count;
+    printf("page_pm_batch_next()/%d %d %d\n",
+                __LINE__, batch_count, fix_count);
+    update_batch_count();
+    update_fix_count();
+}
+
+void
+page_pm_fix_done()
+{
+    if (!doing_batch) return;
+    --fix_count;
+    update_fix_count();
+    // printf("page_pm_fix_done()/%d %d %d\n", __LINE__, batch_count, fix_count);
+}
+
+void
+page_pm_batch_done()
+{
+    if (!doing_batch) return;
+    batch_count = real_batch_count;
+    fix_count   = real_fix_count;
+    printf("page_pm_batch_done()/%d %d %d\n",
+                __LINE__, batch_count, fix_count);
+    update_fix_count();
+    update_batch_count();
+}
+
+//-------------------------------------------------------------------------------------
+//
+//              create_range_controls()
+//
+//      Create the controls for the "run" and the "test" pages.
+//      Some are shared.
+//
+//-------------------------------------------------------------------------------------
+
+void create_range_controls(GtkWidget* window, GtkWidget* table, bool test)
+{
+    GtkWidget* box;
+    GtkObject* adj;
+    GtkWidget* scale;
+    GtkWidget* label;
+
+if (!test)
+{
+    //--------------------------------------------------------------------------
+    //          Accuracy Mask
+    //--------------------------------------------------------------------------
+    box = gtk_hbox_new (FALSE, 6);
+    gtk_container_set_border_width (GTK_CONTAINER (box), 0);
+
+    label = gtk_label_new("Accuracy Mask");
+    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+    gtk_widget_show(label);
+
+    adj = gtk_adjustment_new ((gdouble) accuracy_mask, 0.0, 1001.0, 1.0, 1.0, 1.0);
+    g_signal_connect (G_OBJECT (adj), "value_changed",
+                      G_CALLBACK (cb_accuracy_mask), (gpointer) adj);
+    scale = gtk_hscale_new (GTK_ADJUSTMENT (adj));
+    scale_init(GTK_SCALE(scale));
+    gtk_widget_show(scale);
+
+    gtk_box_pack_start (GTK_BOX (box), scale, TRUE, TRUE, 0);
+    //gtk_widget_show(box);
+
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 0, 1, 11, 12);
+    wid_box_accuracy_mask = box;
+
+    //--------------------------------------------------------------------------
+    //          Timeout (0..64)
+    //          0 == forever.
+    //--------------------------------------------------------------------------
+    box = gtk_hbox_new (FALSE, 6);
+    gtk_container_set_border_width (GTK_CONTAINER (box), 3);
+
+    label = gtk_label_new ("Timeout");
+    gtk_box_pack_start(GTK_BOX (box), label, FALSE, FALSE, 0);
+    gtk_widget_show(label);
+
+    adj = gtk_adjustment_new((gdouble) timeout, 0.0, 65.0, 1.0, 1.0, 1.0);
+    g_signal_connect (G_OBJECT (adj), "value_changed",
+                      G_CALLBACK (cb_timeout), (gpointer) adj);
+    scale = gtk_hscale_new (GTK_ADJUSTMENT (adj));
+    scale_init(GTK_SCALE(scale));
+    gtk_box_pack_start (GTK_BOX (box), scale, TRUE, TRUE, 0);
+    gtk_widget_show(scale);
+
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 1, 2, 11, 12);
+    //gtk_widget_show(box);
+
+    wid_box_timeout = box;
+}
+
+    //--------------------------------------------------------------------------
+    //          Logging checkbox (shared)
+    //--------------------------------------------------------------------------
+    box = gtk_hbox_new (FALSE, 6);
+    GtkWidget* button = gtk_check_button_new_with_label("Logging");
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), nmea_log);
+    g_signal_connect (G_OBJECT (button), "toggled",
+                      G_CALLBACK (cb_nmea_log_value), NULL);
+    gtk_widget_show(button);
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 1);
+    if (wid_log0) wid_log1 = GTK_TOGGLE_BUTTON(button);
+    else          wid_log0 = GTK_TOGGLE_BUTTON(button);
+
+    //gtk_widget_show(box);
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 1, 2, 12, 13);
+
+    //--------------------------------------------------------------------------
+    //          fix rate (0..64 seconds)
+    //          0 == native.
+    //--------------------------------------------------------------------------
+    box = gtk_hbox_new (FALSE, 0);
+    gtk_container_set_border_width (GTK_CONTAINER (box), 0);
+
+    label = gtk_label_new ("Fix rate");
+    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 2);
+    gtk_widget_show(label);
+
+    button = create_arrow_button(GTK_ARROW_LEFT, -1);
+    gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
+
+    adj = gtk_adjustment_new ((gdouble) fix_rate, 0.0, 64.0, 1.0,
+                                                            10.0, 10.0);
+    g_signal_connect (G_OBJECT (adj), "value_changed",
+                          G_CALLBACK (cb_fix_rate), (gpointer) adj);
+    if (wid_fix_rate0) wid_fix_rate1 = GTK_ADJUSTMENT(adj);
+    else               wid_fix_rate0 = GTK_ADJUSTMENT(adj);
+    scale = gtk_hscale_new (GTK_ADJUSTMENT(adj));
+    scale_init(GTK_SCALE(scale));
+    gtk_box_pack_start (GTK_BOX (box), scale, TRUE, TRUE, 0);
+    gtk_widget_show(scale);
+
+    button = create_arrow_button(GTK_ARROW_RIGHT, +1);
+    gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
+
+    if (wid_fix_box0) wid_fix_box1 = box;
+    else              wid_fix_box0 = box;
+
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 0, 1, 12, 13);
+    gtk_widget_show (box);
+
+    if (!test) return;
+
+    //--------------------------------------------------------------------------
+    //          Fix start selection
+    //          COLD, WARM, HOT, SNR Factory test.
+    //          COLD+LTO, WARM+LTO
+    //--------------------------------------------------------------------------
+
+    box = gtk_hbox_new (FALSE, 6);
+    box_fix_type = box;
+    gtk_container_set_border_width (GTK_CONTAINER (box), 3);
+
+    label = gtk_label_new ("Fix type");
+    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+    gtk_widget_show (label);
+
+    GtkWidget* opt  = gtk_option_menu_new();
+    GtkWidget* menu = gtk_menu_new();
+
+    GtkWidget* item = make_menu_item ("cold", G_CALLBACK (cb_pos_menu_select));
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+    item = make_menu_item ("cold (no LTO)", G_CALLBACK (cb_pos_menu_select)); 
+    gtk_menu_shell_append (GTK_MENU_SHELL(menu), item);
+
+    item = make_menu_item ("warm", G_CALLBACK (cb_pos_menu_select)); 
+    gtk_menu_shell_append (GTK_MENU_SHELL(menu), item);
+
+    item = make_menu_item ("warm (no LTO)", G_CALLBACK (cb_pos_menu_select));
+    gtk_menu_shell_append (GTK_MENU_SHELL(menu), item);
+
+    item = make_menu_item ("hot", G_CALLBACK (cb_pos_menu_select));
+    gtk_menu_shell_append (GTK_MENU_SHELL(menu), item);
+
+    item = make_menu_item ("SNR", G_CALLBACK (cb_pos_menu_select));
+    gtk_menu_shell_append (GTK_MENU_SHELL(menu), item);
+
+    gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
+    gtk_option_menu_set_history(GTK_OPTION_MENU(opt), 4);    // [default] is "hot"
+    gtk_box_pack_start (GTK_BOX (box), opt, TRUE, TRUE, 0);
+    gtk_widget_show (opt);
+
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 1, 2, 11, 12);
+    gtk_widget_show (box);
+
+{
+    //--------------------------------------------------------------------------
+    //          Number of fixes (1..n)
+    //--------------------------------------------------------------------------
+    box = gtk_hbox_new (FALSE, 6);
+    gtk_container_set_border_width (GTK_CONTAINER (box), 0);
+
+    label = gtk_label_new ("Fix count");
+    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+    gtk_widget_show (label);
+
+    adj = gtk_adjustment_new ((gdouble) fix_count, 0.0, 1100.0, 1.0, 1.0, 1.0);
+    g_signal_connect (G_OBJECT (adj), "value_changed",
+                      G_CALLBACK (cb_fix_count), (gpointer) adj);
+    wid_fix_adj = GTK_ADJUSTMENT(adj);
+    scale = gtk_hscale_new(wid_fix_adj);
+    scale_init(GTK_SCALE(scale));
+    gtk_box_pack_start (GTK_BOX (box), scale, TRUE, TRUE, 0);
+    gtk_widget_show (scale);
+
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 1, 2, 10, 11);
+    wid_fix_count = box;
+
+    //--------------------------------------------------------------------------
+    //          Number of batches (0..n)
+    //          0 == forever.
+    //--------------------------------------------------------------------------
+    box = gtk_hbox_new (FALSE, 6);
+    gtk_container_set_border_width (GTK_CONTAINER (box), 3);
+
+    label = gtk_label_new ("Batches");
+    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+    gtk_widget_show (label);
+
+    adj = gtk_adjustment_new((gdouble) batch_count, 0.0, 1100.0, 1.0, 1.0, 1.0);
+    g_signal_connect (G_OBJECT (adj), "value_changed",
+                      G_CALLBACK (cb_batch_count), (gpointer) adj);
+    wid_batch_adj = GTK_ADJUSTMENT(adj);
+    scale = gtk_hscale_new(wid_batch_adj);
+    scale_init(GTK_SCALE(scale));
+    gtk_box_pack_start (GTK_BOX (box), scale, TRUE, TRUE, 0);
+    gtk_widget_show (scale);
+
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 0, 1, 10, 11);
+    wid_batch_count = box;
+}
+
+    //--------------------------------------------------------------------------
+    //          Batch mode checkbox
+    //--------------------------------------------------------------------------
+    box = gtk_hbox_new (FALSE, 6);
+    button = gtk_check_button_new_with_label("Batch");
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
+    g_signal_connect (G_OBJECT (button), "toggled",
+                      G_CALLBACK (cb_batch_allowed), NULL);
+    gtk_widget_show(button);
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 1);
+    wid_batch_mode = button;
+
+    //--------------------------------------------------------------------------
+    //          Simulator checkbox
+    //--------------------------------------------------------------------------
+    button = gtk_check_button_new_with_label("Simulator");
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), using_simulator);
+    g_signal_connect (G_OBJECT (button), "toggled",
+                      G_CALLBACK (cb_simulator_value), NULL);
+    gtk_widget_show(button);
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 1);
+    wid_simulator = button;
+
+    gtk_widget_show(box);
+    gtk_table_attach_defaults(GTK_TABLE (table), box, 0, 1, 11, 12);
+}
+
+
+//------------------------------------------------------------------------------
+//
+//      GLLIN parameter setting.
+//
+//------------------------------------------------------------------------------
+
+static int argMax;
+static int argc;
+static const char** argv;
+
+void addArg(const char* s)
+{
+    if (argc < argMax)
+    {
+        argv[  argc] = s;
+        argv[++argc] = 0;
+    }
+}
+
+void addArgInt(int n, char* s)
+{
+    if (argc < argMax)
+    {
+        sprintf(s, "%d", n);
+        addArg(s);
+    }
+}
+
+extern void on_clicked_start(GtkWidget* widget, gpointer data);
+
+void
+pm_controls_nmea_epoch_done(void)
+{
+    //      Trigger the stress test change...
+    if (!doing_stress) return;
+
+    if (--stress_count > 0) return;
+
+    printf("pm_controls_nmea_epoch_done/%d %d %d\n",
+                __LINE__, doing_stress, fix_count);
+
+    on_clicked_start(0, 0);             // Stop
+    sleep(2);                           // slight pause for GLLIN to exit.
+
+    if (doing_ptf)
+    {
+        on_clicked_start(0, (gpointer) 1);  // Restart (single shot)
+    }
+    else
+    {
+        on_clicked_start(0, 0);             // Restart.
+    }
+}
+
+void
+gllin_arg_set(int arg_max, int* pArgc, const char** pp_argv)
+{
+    argc   = *pArgc;
+    argMax = arg_max;
+    argv   = pp_argv;
+
+    if (doing_reset_gps)
+    {
+        addArg("-recover");
+        *pArgc = argc;
+        return;
+    }
+
+    if (doing_ptf)
+    {
+        addArg("+ptf");
+        static char sTO[8];
+        if (set_timeout)
+        {
+            addArg("-to");
+            addArgInt(set_timeout, sTO);
+        }
+
+        static char sAM[8];
+        if (set_accuracy_mask)
+        {
+            addArg("-am");
+            addArgInt(accuracy_mask, sAM);
+        }
+    }
+    else
+    {
+        static char sFixRate[4];
+        addArg("-periodic");                    //  Periodic fix rate
+        addArgInt(fix_rate, sFixRate);
+    }
+
+    doing_stress = false;
+
+    if (doing_batch)
+    {
+        int count = fix_count;
+        if (!count)
+        {
+            count = 10 + (rand() & 0xFF);
+        }
+        printf("%s/%d Starting %s test  count %d\n", __FILE__, __LINE__,
+                        (batch_count) ? "batch" : "stress", count);
+        if (batch_count)
+        {
+            static char sBatchCount[32];
+            static char sFixCount[32];
+
+            addArg("-batch");
+            addArg(start_type);
+            addArgInt(batch_count, sBatchCount);
+            addArgInt(count,   sFixCount);
+        }
+        else
+        {
+            doing_stress = true;
+            stress_count = count;
+        }
+    }
+    else
+    {
+        addArg(start_type);
+    }
+
+    if (using_simulator) addArg("+SIM");
+    if (!allow_lto)      addArg("-lto");
+    if (nmea_log)        addArg("+nmea"); else addArg("-nmea");
+
+    addArg("+np");
+
+    *pArgc = argc;
+}
+
+void
+pm_report(FILE* f, bool stress)
+{
+    if (stress)
+    {
+        if (doing_reset_gps)
+        {
+            fprintf(f, "Reset GPS hardware\n");
+        }
+
+        if (doing_stress)
+        {
+            fprintf(f, "Running stress test.  %d fixes%s\n",
+                            stress_count,
+                            (fix_count) ? "" : " (random)");
+        }
+        if (doing_batch)
+        {
+            fprintf(f, "Running batch test %d x %d (%d x %d remain)\n",
+                            real_batch_count, real_fix_count,
+                                 batch_count,      fix_count );
+        }
+        else
+        {
+            fprintf(f, "Not a batch test\n");
+        }
+    }
+    else
+    {
+        if (doing_ptf)
+        {
+            fprintf(f, "Push to fix.\n");
+            if (set_timeout)
+                fprintf(f, "Position fix timeout %d seconds\n", set_timeout);
+            if (set_accuracy_mask)
+                fprintf(f, "Accuracy mask %d meters\n", accuracy_mask);
+        }
+        else if (fix_rate)
+        {
+            if (1 == fix_rate)
+                fprintf(f, "Compute a fix every second\n");
+            else 
+                fprintf(f, "Compute a fix every %d seconds\n", fix_rate);
+        }
+        else
+        {
+            fprintf(f, "Compute a fix as fast as possible\n");
+        }
+        if (using_simulator)
+            fprintf(f, "Connected to a GPS simulator.\n");
+        if (!allow_lto)
+            fprintf(f, "LTO is suppressed\n");
+        if (!nmea_log)
+            fprintf(f, "NMEA logging is suppressed\n");
+    }
+
+    if (strcmp(start_type,"hot"))
+        fprintf(f, "Simulate a %s start\n", start_type);
+    else
+        fprintf(f, "Performing a %s start\n", start_type);
+}

Added: developers/olv/openmoko-agpsui2/src/sv_bar.h
===================================================================
--- developers/olv/openmoko-agpsui2/src/sv_bar.h	2007-11-07 15:54:27 UTC (rev 3370)
+++ developers/olv/openmoko-agpsui2/src/sv_bar.h	2007-11-07 17:07:34 UTC (rev 3371)
@@ -0,0 +1,103 @@
+/*
+ * Copyright © 2007 Global Locate.
+ *
+ * Written by Ken Yale.
+ *
+ * This program 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef SV_BAR_H__
+#define SV_BAR_H__
+
+enum
+{
+    MIN_ELEVATION  = 10,    // The smallest legible angle.
+    FONT_WIDTH  = 12,
+    FONT_HEIGHT = 20,
+    DB_HZ_to_DBM = -173,
+    N_AVG = 60,
+    MAX_SVS = 14,
+    SEP_WIDTH = 3,          // 3 pixels between bars.
+    BAR_HEIGHT = 300,       // 300 pixels tall.
+    PIXMAP_WIDTH = 476,     // later --- get from the window somwhow.
+    LARGE_WINDOW_WIDTH = PIXMAP_WIDTH - 80,
+                            // slightly smaller than LARGE_WINDOW_HEIGHT??
+    DEGREE_64 = 64         // Minimum arc drawing is 1/64 of a degree
+
+};
+
+typedef struct SV_bar
+{
+    int  prn;
+    int  ss;
+    int  ss_max;
+    int  ss_min;
+    int  az;
+    int  el;
+    bool use;
+    int  avg[N_AVG];
+    int  nAvg;
+    int  sumAvg;
+    int  indexAvg;
+    unsigned long lastUpdate;
+    unsigned long ss_max_time;
+    unsigned long ss_min_time;
+
+    void init()
+    {
+        nAvg     = 0;
+        sumAvg   = 0;
+        indexAvg = 0;
+        use      = false;
+        ss_max   =  0;
+        ss_max_time = 0;
+        ss_min   = 60;
+        ss_min_time = 0;
+    };
+
+    void add_ss()
+    {
+        if (++indexAvg >= N_AVG)
+        {
+            indexAvg = 0;
+        }
+        if (++nAvg > N_AVG)
+        {
+            sumAvg -= avg[indexAvg];
+        }
+        avg[indexAvg] = ss;
+        sumAvg += ss;
+    };
+
+    int avg_ss()
+    {
+        if (!use) return 0;
+        if (nAvg < 1) return 0;
+        if (nAvg < N_AVG) return sumAvg/nAvg;
+        return (sumAvg - 1 + N_AVG/2) / N_AVG;
+    };
+
+    //  Return a number between -100 and +100 along the X and Y axes.
+    void get_xy(int&x, int& y);
+    static int scale_radius(int r);
+
+    static int  nSS;
+    static bool changed;
+    static int  leastSamplesAveraged;
+};
+
+extern SV_bar bars[MAX_SVS];
+
+#endif





More information about the commitlog mailing list