diff options
Diffstat (limited to 'apps')
381 files changed, 84806 insertions, 0 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt new file mode 100755 index 000000000..fe8c057fe --- /dev/null +++ b/apps/ChangeLog.txt @@ -0,0 +1,148 @@ +5.19 2011-03-12 Gregory Nutt <gnutt@nuttx.org> + + * Initial version of the apps/ directory was released as contributed by + Uros Platise. + +6.0 2011-03-21 Gregory Nutt <gnutt@nuttx.org> + + * README.txt -- README cosmetics + * hello/ -- hello world minor changes + * Makefile -- Makefile cosmetics (I am slowly adding the Darjeeling JVM) + * Make.defs -- New file adds common make definitions for applications. + * hello/Makefile -- Now uses new Make.defs definitions. Added README.txt. + * apps/poweroff -- New application to turn off board power. + * Moved NSH library, netutils, and examples from the nuttx/ directory to + the apps/ directory + * Moved exec_nuttapp machinery into the nuttapp/ directory. + +6.1 2011-04-10 Gregory Nutt <gnutt@nuttx.org> + + * Creation of auto-generated header files now occurs during the context + build phase. + * Added sdcard insert and eject, nsh command '?' and some code remarks + * Renamed nuttapp to namedapp + * namedapp/binfs.c -- Create a tiny filesystem that can be used + to show the internal named apps under /bin. + * Numerous fixes to build system required to support building with native + Windows toolchain. + +6.2 2011-05-06 Gregory Nutt <gnutt@nuttx.org> + + * apps/examples/nxffs: Add a test a a configuration that will be used to + verify NXFFS. + +6.3 2011-05-15 Gregory Nutt <gnutt@nuttx.org> + + * apps/interpreter: Add a directory to hold interpreters. The Pascal add- + on module now installs and builds under this directory. + * apps/interpreter/ficl: Added logic to build Ficl (the "Forth Inspired + Command Language"). See http://ficl.sourceforge.net/. + * apps/netutils/dhcpc, dhcpcd, and tftp. If these directories are included + in the configuration but CONFIG_NET_UDP is disable (which is not very wise), + then a make error occurs because tools/mkdep.sh is called with no files. + * system/free: Move Uros' custom free command from vsn/free + * system/install: Add a new install command submitted by Uros Platise. + * examples/rgmp. Add a placeholder for an RGMP build example. + RGMP is a project for running GPOS and RTOS simultaneously on + multi-processor platforms. See http://rgmp.sourceforge.net/wiki/index.php/Main_Page + for further information about RGMP. NOTE: This is an empty example + on initial check-in. + +6.4 2011-06-06 Gregory Nutt <gnutt@nuttx.org> + + * nshlib/nsh_netcmds.c: If a network device name and IP address are provided + with the ifconfig command, then this command will now set the network address. + (Contributed by Yu Qiang). + * netutils/ftpc: A library to support client-side FTP. + * examples/ftpc: A simple add-on to the NSH. From NSH, you can start + this simple FTP shell to transfer files to/from a remote FTP server. + +6.5 2011-06-21 Gregory Nutt <gnutt@nuttx.org> + + * netutils/ftpc: Simpflication and size reduction. + +6.6 2011-07-11 Gregory Nutt <gnutt@nuttx.org> + + * Make.defs, namedapp/namedapp.c: Several structural changes made to get a + clean compile under the ez80 ZDS-II toolchain (no design changes). + * apps/examples/buttons: Add a test for the new standardized button interfaces + * apps/examples/nxtext: Add another NX graphics test. This one focus on + placing text on the background while pop-up windows occur. Text should + continue to update normally with or without the popup windows present. + +6.7 2011-08-02 Gregory Nutt <gnutt@nuttx.org> + + * apps/examples/nx and nxtext: These examples can now be built as NSH + "built-in" commands. + * apps/examples/nxhello: The simplest graphics example: It just says + "Hello, World!" in the center of the display. This example can also be + built as an NSH "built-in" command. + * apps/examples/nx, ntext, and nxhello: All updated to use the new + NuttX font interfaces. + * apps/examples/nximage: Another super simple graphics example: It just puts + the NuttX logo in the center of the display. This example can also be + built as an NSH "built-in" command. + * apps/examples/usbstorage: Can now be built as two NSH "built-in" commands: + 'msconn' will connect the USB mass storage device; 'msdis' will disconnect + the USB storage device. + * apps/examples/nx*: All NX header files moved from nuttx/include/nuttx to + nuttx/include/nuttx/nx. + * apps/examples/usbstorage: Added instrumentation to monitor memory usage + to check for memory leaks in the USB storage driver. + * apps/examples/nxhello/nxhello_bkgd.c: Fix handling of allocated glyph + memory. + +6.8 2011-08-11 Gregory Nutt <gnutt@nuttx.org> + + * apps/examples/nxlines: Added a test for NX line drawing capabilities. + +6.9 2011-09-11 Gregory Nutt <gnutt@nuttx.org> + + * apps/examples/nxlines: Extend the line drawing text to include drawing + of circles. + * apps/system/i2c: Add an I2C test tool that should help to bring up I2C + devices (when it is fully functional). + * apps/nshlib/nsh_timcmds.c: Add the date command that can be used to + show or set the time (only if CONFIG_RTC is set). + +6.10 2011-10-06 Gregory Nutt <gnutt@nuttx.org> + + * apps/system/i2c: Add repitition and address auto-incrementing so that + and command can be executed numerous times. Add a new verify command + that will write to a register, read from register, and verify that + returned value. + * apps/graphics/tiff: Add a library that can be used to create TIFF files. + * apps/examples/tiff: Add a unit test for the TIFF file creation logic + * apps/examples/lcdrw: Add a test to verify if you can or can or read + data from an LCD correctly. + * apps/examples/usbterm: A USB terminal example.. more of a USB chat or + serial bridge: Data received on local console echoed via USB serial; + data received on USB serial is echoed on the local console. + * apps/examples/touchscreen: Add a simple, generic test for any + touschscreen driver. + * Makefile: The apps/ Makefile now checks for an apps/external directory + or symbolic link. If such a directory/link exists (and has a Makefile), + it will be added to the apps/ build. This allows external directories + to be included into the apps/ build by simply creating a symbolic link. + +6.11 2011-11-12 Gregory Nutt <gnutt@nuttx.org> + + (No major changes from 6.10) + +6.12 2011-12-06 Gregory Nutt <gnutt@nuttx.org> + + * apps/examples/buttons: The button test can now be executed as an NSH + built in command. + +6.13 2012-xx-xx Gregory Nutt <gnutt@nuttx.org> + + * apps/examples/dhcpd: May now be built as an NSH built-in application + by setting CONFIG_NSH_BUILTIN_APPS. + * apps/netutils/dhcpd/dhcpd.c: Fix several problems using host order address + where network addresses expected (and vice versa). + * apps/examples/nettest: May now be built as an NSH built-in application + by setting CONFIG_NSH_BUILTIN_APPS. + * apps/examples/nettest: Correct some build issues with the nettest is + built for performance evaluation. + * apps/examples/adc: Add a very simple test to drive and test an ADC + driver. diff --git a/apps/Make.defs b/apps/Make.defs new file mode 100755 index 000000000..f37a654c4 --- /dev/null +++ b/apps/Make.defs @@ -0,0 +1,41 @@ +############################################################################ +# apps/Make.defs +# Common make definitions provided to all applications +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +define REGISTER + @echo "Register: $1" + @echo "{ \"$1\", $2, $3, $4 }," >> "$(APPDIR)/namedapp/namedapp_list.h" + @echo "EXTERN int $4(int argc, char *argv[]);" >> "$(APPDIR)/namedapp/namedapp_proto.h" +endef diff --git a/apps/Makefile b/apps/Makefile new file mode 100644 index 000000000..f73f0eaac --- /dev/null +++ b/apps/Makefile @@ -0,0 +1,132 @@ +############################################################################ +# apps/Makefile +# +# Copyright (C) 2011 Uros Platise. All rights reserved. +# Authors: Uros Platise <uros.platise@isotel.eu> +# Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/Make.defs + +APPDIR = ${shell pwd} + +# Application Directories + +# CONFIGURED_APPS is the list of all configured built-in directories/built +# action. It is created by the configured appconfig file (a copy of which +# appears in this directory as .config) +# SUBDIRS is the list of all directories containing Makefiles. It is used +# only for cleaning. namedapp must always be the first in the list. This +# list can be extended by the .config file as well + +CONFIGURED_APPS = +SUBDIRS = examples graphics interpreters namedapp nshlib netutils system vsn + +-include .config + +# INSTALLED_APPS is the list of currently available application directories. It +# is the same as CONFIGURED_APPS, but filtered to exclude any non-existent +# application directory. namedapp is always in the list of applications to be +# built. + +INSTALLED_APPS = namedapp + +# Create the list of available applications (INSTALLED_APPS) + +define ADD_BUILTIN +INSTALLED_APPS += ${shell if [ -r $1/Makefile ]; then echo "$1"; fi} +endef + +$(foreach BUILTIN, $(CONFIGURED_APPS), $(eval $(call ADD_BUILTIN,$(BUILTIN)))) + +# The external/ directory may also be added to the INSTALLED_APPS. But there +# is no external/ directory in the repository. Rather, this directory may be +# provided by the user (possibly as a symbolic link) to add libraries and +# applications to the standard build from the repository. + +INSTALLED_APPS += ${shell if [ -r external/Makefile ]; then echo "external"; fi} +SUBDIRS += ${shell if [ -r external/Makefile ]; then echo "external"; fi} + +# The final build target + +BIN = libapps$(LIBEXT) + +# Build targets + +all: $(BIN) +.PHONY: $(INSTALLED_APPS) context depend clean distclean + +$(INSTALLED_APPS): + @$(MAKE) -C $@ TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; + +$(BIN): $(INSTALLED_APPS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $@, $${obj}); \ + done ; ) + +.context: + @for dir in $(INSTALLED_APPS) ; do \ + rm -f $$dir/.context ; \ + $(MAKE) -C $$dir TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" context ; \ + done + @touch $@ + +context: .context + +.depend: context Makefile $(SRCS) + @for dir in $(INSTALLED_APPS) ; do \ + rm -f $$dir/.depend ; \ + $(MAKE) -C $$dir TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" depend ; \ + done + @touch $@ + +depend: .depend + +clean: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + @rm -f $(BIN) *~ .*.swp *.o + $(call CLEAN) + +distclean: clean + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir distclean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + @rm -f .config .context .depend + @( if [ -e external ]; then \ + echo "********************************************************"; \ + echo "* The external directory/link must be removed manually *"; \ + echo "********************************************************"; \ + fi; \ + ) + + diff --git a/apps/README.txt b/apps/README.txt new file mode 100644 index 000000000..f1fb124c4 --- /dev/null +++ b/apps/README.txt @@ -0,0 +1,146 @@ +Application Folder +================== + +Contents +-------- + + General + Directory Location + Named Applications + Named Startup main() function + NuttShell (NSH) Built-In Commands + Synchronous Built-In Commands + Application Configuration File + Example Named Application + +General +------- +This folder provides various applications found in sub-directories. These +applications are not inherently a part of NuttX but are provided you help +you develop your own applications. The apps/ directory is a "break away" +part of the configuration that you may chose to use or not. + +Directory Location +------------------ +The default application directory used by the NuttX build should be named +apps/ (or apps-x.y/ where x.y is the NuttX version number). This apps/ +directoy should appear in the directory tree at the same level as the +NuttX directory. Like: + + . + |- nuttx + | + `- apps + +If all of the above conditions are TRUE, then NuttX will be able to +find the application directory. If your application directory has a +different name or is location at a different position, then you will +have to inform the NuttX build system of that location. There are several +ways to do that: + +1) You can define CONFIG_APPS_DIR to be the full path to your application + directory in the NuttX configuration file. +2) You can provide the path to the application directory on the command line + like: make APPDIR=<path> or make CONFIG_APPS_DIR=<path> +3) When you configure NuttX using tools/configure.sh, you can provide that + path to the application directory on the configuration command line + like: ./configure.sh -a <app-dir> <board-name>/<config-name> + +Named Applications +------------------ +NuttX also supports applications that can be started using a name string. +In this case, zpplication entry points with their requirements are gathered +together in two files: + + - namedapp/namedapp_proto.h Entry points, prototype function + - namedapp/namedapp_list.h Application specific information and requirements + +The build occurs in several phases as different build targets are executed: +(1) context, (2) depend, and (3) default (all). Application information is +collected during the make context build phase. + +To execute an application function: + + exec_namedapp() is defined in the nuttx/include/apps/apps.h + +NuttShell (NSH) Built-In Commands +--------------------------------- +One use of named applications is to provide a way of invoking your custom +application through the NuttShell (NSH) command line. NSH will support +a seamless method invoking the applications, when the following option is +enabled in the NuttX configuration file: + + CONFIG_NSH_BUILTIN_APPS=y + +Applications registered in the apps/namedapp/namedapp_list.h file will then +be accessible from the NSH command line. If you type 'help' at the NSH +prompt, you will see a list of the registered commands. + +Synchronous Built-In Commands +----------------------------- +By default, built-in commands started from the NSH command line will run +asynchronously with NSH. If you want to force NSH to execute commands +then wait for the command to execute, you can enable that feature by +adding the following to the NuttX configuration file: + +CONFIG_SCHED_WAITPID=y + +The configuration option enables support for the waitpid() RTOS interface. +When that interface is enabled, NSH will use it to wait, sleeping until +the built-in command executes to completion. + +Of course, even with CONFIG_SCHED_WAITPID=y defined, specific commands +can still be forced to run asynchronously by adding the ampersand (&) +after the NSH command. + +Application Configuration File +------------------------------ +A special configuration file is used to configure which applications +are to be included in the build. The source for this file is +configs/<board>/<configuration>/appconfig. The existence of the appconfig +file in the board configuration directory is sufficient to enable building +of applications. + +The appconfig file is copied into the apps/ directory as .config when +NuttX is configured. .config is included in the toplevel apps/Makefile. +As a minimum, this configuration file must define files to add to the +CONFIGURED_APPS list like: + + CONFIGURED_APPS += vsn/hello vsn/poweroff vsn/jvm + +Named Start-Up main() function +------------------------------ +A named application can even be used as the main, start-up entry point +into your embedded software. When the user defines this option in +the NuttX configuration file: + + CONFIG_BUILTIN_APP_START=<application name> + +that application shall be invoked immediately after system starts +*instead* of the normal, default "user_start" entry point. +Note that <application name> must be provided as: "hello", +will call: + + int hello_main(int argc, char *argv[]) + +Example Named Application +------------------------- +An example application skeleton can be found under the vsn/hello +sub-directory. This example shows how a named application can be added +to the project. One must define: + + 1. create sub-directory as: appname + 2. provide entry point: appname_main() + 3. set the requirements in the file: Makefile, specially the lines: + + APPNAME = appname + PRIORITY = SCHED_PRIORITY_DEFAULT + STACKSIZE = 768 + ASRCS = asm source file list as a.asm b.asm ... + CSRCS = C source file list as foo1.c foo2.c .. + + 4. add application in the apps/.config + + + + diff --git a/apps/examples/Makefile b/apps/examples/Makefile new file mode 100644 index 000000000..d549fe28e --- /dev/null +++ b/apps/examples/Makefile @@ -0,0 +1,118 @@ +############################################################################ +# apps/examples/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration + +# Sub-directories + +SUBDIRS = adc buttons dhcpd ftpc hello helloxx hidkbd igmp lcdrw mm mount \ + nettest nsh null nx nxffs nxflat nxhello nximage nxlines \ + nxtext ostest pashello pipe poll rgmp romfs sendmail serloop \ + thttpd tiff touchscreen udp uip usbserial usbstorage usbterm wget wlan + +# Sub-directories that might need context setup + +CNTXTDIRS = + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +CNTXTDIRS += adc +endif +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +CNTXTDIRS += dhcpd +endif +ifeq ($(CONFIG_EXAMPLES_HELLOXX_BUILTIN),y) +CNTXTDIRS += helloxx +endif +ifeq ($(CONFIG_EXAMPLES_LCDRW_BUILTIN),y) +CNTXTDIRS += lcdrw +endif +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +CNTXTDIRS += nettest +endif +ifeq ($(CONFIG_EXAMPLES_NX_BUILTIN),y) +CNTXTDIRS += nx +endif +ifeq ($(CONFIG_EXAMPLES_NXHELLO_BUILTIN),y) +CNTXTDIRS += nxhello +endif +ifeq ($(CONFIG_EXAMPLES_NXIMAGE_BUILTIN),y) +CNTXTDIRS += nximage +endif +ifeq ($(CONFIG_EXAMPLES_LINES_BUILTIN),y) +CNTXTDIRS += nxlines +endif +ifeq ($(CONFIG_EXAMPLES_NXTEXT_BUILTIN),y) +CNTXTDIRS += nxtext +endif +ifeq ($(CONFIG_EXAMPLES_TIFF_BUILTIN),y) +CNTXTDIRS += tiff +endif +ifeq ($(CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN),y) +CNTXTDIRS += touchscreen +endif +ifeq ($(CONFIG_EXAMPLES_USBSTRG_BUILTIN),y) +CNTXTDIRS += usbstorage +endif +ifeq ($(CONFIG_EXAMPLES_USBTERM_BUILTIN),y) +CNTXTDIRS += usbterm +endif + +all: nothing +.PHONY: nothing context depend clean distclean + +nothing: + +context: + @for dir in $(CNTXTDIRS) ; do \ + $(MAKE) -C $$dir context TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +depend: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir depend TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +clean: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +distclean: clean + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir distclean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +-include Make.dep + diff --git a/apps/examples/README.txt b/apps/examples/README.txt new file mode 100644 index 000000000..4460e2c66 --- /dev/null +++ b/apps/examples/README.txt @@ -0,0 +1,1140 @@ +examples +^^^^^^^^ + + appconfig and CONFIG_APPS + + The examples directory contains several sample applications that + can be linked with NuttX. The specific example is selected in the + configs/<board-name>/appconfig file via the CONFIGURED_APPS setting. + This setting provides the path to the directory containing the + application Makefile (this path is a relative to the apps/ top- + level directory). For example, + + CONFIGURE_APPS += examples/ostest + + Selects the examples/ostest example. + + Built-In functions + + Some of the examples may be built as "built-in" functions that + can be executed at run time (rather than as NuttX "main" programs). + These "built-in" examples can be also be executed from the NuttShell + (NSH) command line. In order to configure these built-in NSH + functions, you have to set up the following: + + - CONFIG_NSH_BUILTIN_APPS - Enable support for external registered, + "named" applications that can be executed from the NSH + command line (see apps/README.txt for more information). + - CONFIG_EXAMPLES_XYZ_BUILTIN -- Build the XYZ example as a "built-in" + that can be executed from the NSH command line (where XYZ is + the specific example. See the following for examples that + support this option). + +examples/adc +^^^^^^^^^^^^ + + A mindlessly simple test of an ADC devices. It simply reads from the + ADC device and dumps the data to the console forever. + + - CONFIG_NSH_BUILTIN_APPS - Build the ADC test as an NSH built-in function. + Default: Built as a standalone problem + - CONFIG_EXAMPLES_ADC_DEVPATH - The path to the ADC device. Default: /dev/adc0 + - CONFIG_EXAMPLES_ADC_NSAMPLES - If CONFIG_NSH_BUILTIN_APPS + is defined, then the number of samples is provided on the command line + and this value is ignored. Otherwise, this number of samples is + collected and the program terminates. Default: Samples are collected + indefinitely. + - CONFIG_EXAMPLES_ADC_GROUPSIZE - The number of samples to read at once. + Default: 4 + +examples/buttons +^^^^^^^^^^^^^^^^ + + This is a simple configuration that may be used to test the board- + specific button interfaces. Configuration options: + + CONFIG_ARCH_BUTTONS - Must be defined for button support + CONFIG_EXAMPLE_BUTTONS_MIN - Lowest button number (MIN=0) + CONFIG_EXAMPLE_BUTTONS_MAX - Highest button number (MAX=7) + + CONFIG_ARCH_IRQBUTTONS - Must be defined for interrupting button support + CONFIG_EXAMPLE_IRQBUTTONS_MIN - Lowest interrupting button number (MIN=0) + CONFIG_EXAMPLE_IRQBUTTONS_MAX - Highest interrupting button number (MAX=7) + + Name strings for buttons: + + CONFIG_EXAMPLE_BUTTONS_NAME0, CONFIG_EXAMPLE_BUTTONS_NAME1, + CONFIG_EXAMPLE_BUTTONS_NAME2, CONFIG_EXAMPLE_BUTTONS_NAME3, + CONFIG_EXAMPLE_BUTTONS_NAME4, CONFIG_EXAMPLE_BUTTONS_NAME5, + CONFIG_EXAMPLE_BUTTONS_NAME6, CONFIG_EXAMPLE_BUTTONS_NAME7, + + Additional architecture-/board- specific configuration settings may also + be required. + + NOTE: This test exercises internal button driver interfaces. As such, it + relies on internal OS interfaces that are not normally available to a + user-space program. As a result, this example cannot be used if a + NuttX is built as a protected, supervisor kernel (CONFIG_NUTTX_KERNEL). + +examples/dhcpd +^^^^^^^^^^^^^^ + + This examples builds a tiny DCHP server for the target system. + + NOTE: For test purposes, this example can be built as a + host-based DHCPD server. This can be built as follows: + + cd examples/dhcpd + make -f Makefile.host TOPDIR=<nuttx-directory> + + NuttX configuration settings: + + CONFIG_NET=y - Of course + CONFIG_NSOCKET_DESCRIPTORS - And, of course, you must allocate some + socket descriptors. + CONFIG_NET_UDP=y - UDP support is required for DHCP + (as well as various other UDP-related + configuration settings) + CONFIG_NET_BROADCAST=y - UDP broadcast support is needed. + + CONFIG_EXAMPLE_DHCPD_NOMAC - (May be defined to use software assigned MAC) + CONFIG_EXAMPLE_DHCPD_IPADDR - Target IP address + CONFIG_EXAMPLE_DHCPD_DRIPADDR - Default router IP addess + CONFIG_EXAMPLE_DHCPD_NETMASK - Network mask + + See also CONFIG_NETUTILS_DHCPD_* settings described elsewhere + and used in netutils/dhcpd/dhcpd.c. These settings are required + to described the behavior of the daemon. + + Applications using this example will need to provide an appconfig + file in the configuration driver with instruction to build applications + like: + + CONFIGURED_APPS += uiplib + +examples/ftpc +^^^^^^^^^^^^^ + + This is a simple FTP client shell used to exercise the capabilities + of the FTPC library (apps/netutils/ftpc). This example is configured + to that it will only work as a "built-in" program that can be run from + NSH when CONFIG_NSH_BUILTIN_APPS is defined. + + From NSH, the startup command sequence is as follows. This is only + an example, your configration could have different mass storage devices, + mount paths, and FTP directories: + + nsh> mount -t vfat /dev/mmcsd0 /tmp # Mount the SD card at /tmp + nsh> cd /tmp # cd into the /tmp directory + nsh> ftpc xx.xx.xx.xx[:pp] # Start the FTP client + nfc> login <name> <password> # Log into the FTP server + nfc> help # See a list of FTP commands + + where xx.xx.xx.xx is the IP address of the FTP server and pp is an + optional port number. + + NOTE: The ftpc task uses the system console for input/output. It will + not work from NSH over a telnet NSH connection (Well, it will work you + just won't be able to access the command line). + + You may also want to define the following in your configuration file. + Otherwise, you will have not feeback about what is going on: + + CONFIG_DEBUG=y + CONFIG_DEBUG_VERBOSE=y + CONFIG_DEBUG_FTPC=y + +examples/hello +^^^^^^^^^^^^^^ + + This is the mandatory, "Hello, World!!" example. It is little more + than examples/null with a single printf statement. Really useful only + for bringing up new NuttX architectures. + +examples/helloxx +^^^^^^^^^^^^^^^^ + + This is C++ version of the "Hello, World!!" example. It is intended + only to verify that the C++ compiler is functional, that basic C++ + library suupport is available, and that class are instantiated + correctly. + + NuttX configuration settings: + + CONFIG_EXAMPLES_HELLOXX_BUILTIN -- Build the helloxx example as a + "built-in" that can be executed from the NSH command line. + CONFIG_EXAMPLES_HELLOXX_NOSTATICCONST - Set if system does not support + static constructors. + CONFIG_EXAMPLES_HELLOXX_NOSTACKCONST - Set if the system does not + support construction of objects on the stack. + + Also needed: + + CONFIG_HAVE_CXX=y + + And you may have to tinker with the following to get libxx to compile + properly: + + CONFIG_CXX_NEWLONG=y or =n + + The argument of the 'new' operators should take a type of size_t. But size_t + has an unknown underlying. In the nuttx sys/types.h header file, size_t + is typed as uint32_t (which is determined by architecture-specific logic). + But the C++ compiler may believe that size_t is of a different type resulting + in compilation errors in the operator. Using the underlying integer type + Instead of size_t seems to resolve the compilation issues. + +examples/hidkbd +^^^^^^^^^^^^^^^^ + + This is a simple test to debug/verify the USB host HID keyboard class + driver. + + CONFIG_EXAMPLES_HIDKBD_DEFPRIO - Priority of "waiter" thread. + CONFIG_EXAMPLES_HIDKBD_STACKSIZE - Stacksize of "waiter" thread. + +examples/igmp +^^^^^^^^^^^^^ + + This is a trivial test of the NuttX IGMP capability. It present it + does not do much of value -- Much more is needed in order to verify + the IGMP features! + + * CONFIG_EXAMPLE_IGMP_NOMAC + Set if the hardware has no MAC address; one will be assigned + * CONFIG_EXAMPLE_IGMP_IPADDR + Target board IP address + * CONFIG_EXAMPLE_IGMP_DRIPADDR + Default router address + * CONFIG_EXAMPLE_IGMP_NETMASK + Network mask + * CONFIG_EXAMPLE_IGMP_GRPADDR + Multicast group address + + Applications using this example will need to provide an appconfig + file in the configuration driver with instruction to build applications + like: + + CONFIGURED_APPS += uiplib + +examples/lcdrw +^^^^^^^^^^^^^^ + + This example may be used to verify if you can or cannot read data + correct from an LCD interface. At present, this supports only LCDs + with RGB565 color format. + +examples/mm +^^^^^^^^^^^ + + This is a simplified version of the "built-in" memory manager test of + mm/mm_test.c. It is simplified because it does not have access to the + internals of the memory manager as does mm/mm_test.c, but it has the + advantage that it runs in the actual NuttX tasking environment (the + mm/mm_test.c only runs in a PC simulation environment). + +examples/mount +^^^^^^^^^^^^^^ + + This contains a simple test of filesystem mountpoints. + + * CONFIG_EXAMPLES_MOUNT_DEVNAME + The name of the user-provided block device to mount. + If CONFIG_EXAMPLES_MOUNT_DEVNAME is not provided, then + a RAM disk will be configured. + + * CONFIG_EXAMPLES_MOUNT_NSECTORS + The number of "sectors" in the RAM disk used when + CONFIG_EXAMPLES_MOUNT_DEVNAME is not defined. + + * CONFIG_EXAMPLES_MOUNT_SECTORSIZE + The size of each sectors in the RAM disk used when + CONFIG_EXAMPLES_MOUNT_DEVNAME is not defined. + + * CONFIG_EXAMPLES_MOUNT_RAMDEVNO + The RAM device minor number used to mount the RAM disk used + when CONFIG_EXAMPLES_MOUNT_DEVNAME is not defined. The + default is zero (meaning that "/dev/ram0" will be used). + +examples/netttest +^^^^^^^^^^^^^^^^^ + + This is a simple network test for verifying client- and server- + functionality in a TCP/IP connection. + + Applications using this example will need to provide an appconfig + file in the configuration driver with instruction to build applications + like: + + CONFIGURED_APPS += uiplib + +examples/nsh +^^^^^^^^^^^^ + + This directory provides an example of how to configure and use + the NuttShell (NSH) application. NSH is a simple shell + application. NSH is described in its own README located at + apps/nshlib/README.txt + + Applications using this example will need to provide an appconfig + file in the configuration driver with instruction to build applications + like: + + CONFIGURED_APPS += nshlib + + And if networking is included: + + CONFIGURED_APPS += uiplib + CONFIGURED_APPS += dhcpc + CONFIGURED_APPS += resolv + CONFIGURED_APPS += tftp + CONFIGURED_APPS += webclient + +examples/nx +^^^^^^^^^^^ + + This directory contains a simple test of a subset of the NX APIs + defined in include/nuttx/nx/nx.h. The following configuration options + can be selected: + + CONFIG_EXAMPLES_NX_BUILTIN -- Build the NX example as a "built-in" + that can be executed from the NSH command line + CONFIG_EXAMPLES_NX_VPLANE -- The plane to select from the frame- + buffer driver for use in the test. Default: 0 + CONFIG_EXAMPLES_NX_DEVNO - The LCD device to select from the LCD + driver for use in the test: Default: 0 + CONFIG_EXAMPLES_NX_BGCOLOR -- The color of the background. Default depends on + CONFIG_EXAMPLES_NX_BPP. + CONFIG_EXAMPLES_NX_COLOR1 -- The color of window 1. Default depends on + CONFIG_EXAMPLES_NX_BPP. + CONFIG_EXAMPLES_NX_COLOR2 -- The color of window 2. Default depends on + CONFIG_EXAMPLES_NX_BPP. + CONFIG_EXAMPLES_NX_TBCOLOR -- The color of the toolbar. Default depends on + CONFIG_EXAMPLES_NX_BPP. + CONFIG_EXAMPLES_NX_FONTID - Selects the font (see font ID numbers in + include/nuttx/nx/nxfonts.h) + CONFIG_EXAMPLES_NX_FONTCOLOR -- The color of the fonts. Default depends on + CONFIG_EXAMPLES_NX_BPP. + CONFIG_EXAMPLES_NX_BPP -- Pixels per pixel to use. Valid options + include 2, 4, 8, 16, 24, and 32. Default is 32. + CONFIG_EXAMPLES_NX_RAWWINDOWS -- Use raw windows; Default is to + use pretty, framed NXTK windows with toolbars. + CONFIG_EXAMPLES_NX_EXTERNINIT - The driver for the graphics device on + this platform requires some unusual initialization. This is the + for, for example, SPI LCD/OLED devices. If this configuration is + selected, then the platform code must provide an LCD initialization + function with a prototype like: + + #ifdef CONFIG_NX_LCDDRIVER + FAR struct lcd_dev_s *up_nxdrvinit(unsigned int devno); + #else + FAR struct fb_vtable_s *up_nxdrvinit(unsigned int devno); + #endif + + This test can be performed with either the single-user version of + NX or with the multiple user version of NX selected with CONFIG_NX_MULTIUSER. + If CONFIG_NX_MULTIUSER is defined, then the following configuration + options also apply: + + CONFIG_EXAMPLES_NX_STACKSIZE -- The stacksize to use when creating + the NX server. Default 2048 + CONFIG_EXAMPLES_NX_CLIENTPRIO -- The client priority. Default: 100 + CONFIG_EXAMPLES_NX_SERVERPRIO -- The server priority. Default: 120 + CONFIG_EXAMPLES_NX_LISTENERPRIO -- The priority of the event listener + thread. Default 80. + CONFIG_EXAMPLES_NX_NOTIFYSIGNO -- The signal number to use with + nx_eventnotify(). Default: 4 + + If CONFIG_NX_MULTIUSER is defined, then the example also expects the + following settings and will generate an error if they are not as expected: + + CONFIG_DISABLE_MQUEUE=n + CONFIG_DISABLE_SIGNALS=n + CONFIG_DISABLE_PTHREAD=n + CONFIG_NX_BLOCKING=y + +examples/nxffs +^^^^^^^^^^^^^^ + + This is a test of the NuttX NXFFS FLASH file system. This is an NXFFS + stress test and beats on the file system very hard. It should only + be used in a simulation environment! Putting this NXFFS test on real + hardware will most likely destroy your FLASH. You have been warned. + +examples/nxflat +^^^^^^^^^^^^^^^ + + This example builds a small NXFLAT test case. This includes several + test programs under examples/nxflat tests. These tests are build using + the NXFLAT format and installed in a ROMFS file system. At run time, + each program in the ROMFS file system is executed. Requires CONFIG_NXFLAT. + +examplex/nxhello +^^^^^^^^^^^^^^^^ + + A very simple graphics example that just says "Hello, World!" in the + center of the display. + + The following configuration options can be selected: + + CONFIG_EXAMPLES_NXHELLO_BUILTIN -- Build the NXHELLO example as a "built-in" + that can be executed from the NSH command line + CONFIG_EXAMPLES_NXHELLO_VPLANE -- The plane to select from the frame- + buffer driver for use in the test. Default: 0 + CONFIG_EXAMPLES_NXHELLO_DEVNO - The LCD device to select from the LCD + driver for use in the test: Default: 0 + CONFIG_EXAMPLES_NXHELLO_BGCOLOR -- The color of the background. Default + depends on CONFIG_EXAMPLES_NXHELLO_BPP. + CONFIG_EXAMPLES_NXHELLO_FONTID - Selects the font (see font ID numbers in + include/nuttx/nx/nxfonts.h) + CONFIG_EXAMPLES_NXHELLO_FONTCOLOR -- The color of the fonts used in the + background window. Default depends on CONFIG_EXAMPLES_NXHELLO_BPP. + CONFIG_EXAMPLES_NXHELLO_BPP -- Pixels per pixel to use. Valid options + include 2, 4, 8, 16, 24, and 32. Default is 32. + CONFIG_EXAMPLES_NXHELLO_EXTERNINIT - The driver for the graphics device on + this platform requires some unusual initialization. This is the + for, for example, SPI LCD/OLED devices. If this configuration is + selected, then the platform code must provide an LCD initialization + function with a prototype like: + + #ifdef CONFIG_NX_LCDDRIVER + FAR struct lcd_dev_s *up_nxdrvinit(unsigned int devno); + #else + FAR struct fb_vtable_s *up_nxdrvinit(unsigned int devno); + #endif + +examples/nximage +^^^^^^^^^^^^^^^^ + + This is a simple example that just puts the NuttX logo image in the center + of the display. This only works for RGB23 (888), RGB16 (656), RGB8 (332), + and 8-bit greyscale for now. + + CONFIG_EXAMPLES_NXIMAGE_BUILTIN -- Build the NXIMAGE example as a "built-in" + that can be executed from the NSH command line + CONFIG_EXAMPLES_NXIMAGE_VPLANE -- The plane to select from the frame- + buffer driver for use in the test. Default: 0 + CONFIG_EXAMPLES_NXIMAGE_DEVNO - The LCD device to select from the LCD + driver for use in the test: Default: 0 + CONFIG_EXAMPLES_NXIMAGE_BPP -- Pixels per pixel to use. Valid options + include 8, 16, and 24. Default is 16. + CONFIG_EXAMPLES_NXIMAGE_XSCALEp5, CONFIG_EXAMPLES_NXIMAGE_XSCALE1p5, + CONFIG_EXAMPLES_NXIMAGE_XSCALE2p0 -- The logo image width is 160 columns. + One of these may be defined to rescale the image horizontally by .5, 1.5, + or 2.0. + CONFIG_EXAMPLES_NXIMAGE_YSCALEp5, CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5, + CONFIG_EXAMPLES_NXIMAGE_YSCALE2p0 -- The logo image height is 160 rows. + One of these may be defined to rescale the image vertically by .5, 1.5, + or 2.0. + CONFIG_EXAMPLES_NXIMAGE_GREYSCALE -- Grey scale image. Default: RGB. + CONFIG_EXAMPLES_NXIMAGE_EXTERNINIT - The driver for the graphics device on + this platform requires some unusual initialization. This is the + for, for example, SPI LCD/OLED devices. If this configuration is + selected, then the platform code must provide an LCD initialization + function with a prototype like: + + #ifdef CONFIG_NX_LCDDRIVER + FAR struct lcd_dev_s *up_nxdrvinit(unsigned int devno); + #else + FAR struct fb_vtable_s *up_nxdrvinit(unsigned int devno); + #endif + + How was that run-length encoded image produced? + + a. I used GIMP output the image as a .c file. + b. I added som C logic to palette-ize the RGB image in the GIMP .c file + c. Then I add some simple run-length encoding to palette-ized image. + + NOTE: As of this writing, most of the pixel depth, scaling options, and + combinations thereof have not been tested. + +examplex/nxlines +^^^^^^^^^^^^^^^^ + + A very simple graphics example that just exercised the NX line drawing + logic. + + The following configuration options can be selected: + + CONFIG_EXAMPLES_NXLINES_BUILTIN -- Build the NXLINES example as a "built-in" + that can be executed from the NSH command line + CONFIG_EXAMPLES_NXLINES_VPLANE -- The plane to select from the frame- + buffer driver for use in the test. Default: 0 + CONFIG_EXAMPLES_NXLINES_DEVNO - The LCD device to select from the LCD + driver for use in the test: Default: 0 + CONFIG_EXAMPLES_NXLINES_BGCOLOR -- The color of the background. Default + depends on CONFIG_EXAMPLES_NXLINES_BPP. + CONFIG_EXAMPLES_NXLINES_LINEWIDTH - Selects the width of the lines in + pixels (default: 16) + CONFIG_EXAMPLES_NXLINES_LINECOLOR -- The color of the central lines drawn + in the background window. Default depends on CONFIG_EXAMPLES_NXLINES_BPP + (there really is no meaningful default). + CONFIG_EXAMPLES_NXLINES_BORDERWIDTH -- The width of the circular border + drawn in the background window. (default: 4). + CONFIG_EXAMPLES_NXLINES_BORDERCOLOR -- The color of the circular border + drawn in the background window. Default depends on CONFIG_EXAMPLES_NXLINES_BPP + (there really is no meaningful default). + CONFIG_EXAMPLES_NXLINES_CIRCLECOLOR -- The color of the circular region + filled in the background window. Default depends on CONFIG_EXAMPLES_NXLINES_BPP + (there really is no meaningful default). + CONFIG_EXAMPLES_NXLINES_BORDERCOLOR -- The color of the lines drawn in the + background window. Default depends on CONFIG_EXAMPLES_NXLINES_BPP (there + really is no meaningful default). + + CONFIG_EXAMPLES_NXLINES_BPP -- Pixels per pixel to use. Valid options + include 2, 4, 8, 16, 24, and 32. Default is 16. + CONFIG_EXAMPLES_NXLINES_EXTERNINIT - The driver for the graphics device on + this platform requires some unusual initialization. This is the + for, for example, SPI LCD/OLED devices. If this configuration is + selected, then the platform code must provide an LCD initialization + function with a prototype like: + + #ifdef CONFIG_NX_LCDDRIVER + FAR struct lcd_dev_s *up_nxdrvinit(unsigned int devno); + #else + FAR struct fb_vtable_s *up_nxdrvinit(unsigned int devno); + #endif + +examples/nxtext +^^^^^^^^^^^^^^^ + + This directory contains another simple test of a subset of the NX APIs + defined in include/nuttx/nx/nx.h. This text focuses on text displays on + the dispaly background combined with pop-up displays over the text. + The text display will continue to update while the pop-up is visible. + + NOTE: This example will *only* work with FB drivers and with LCD + drivers that support reading the contents of the internal LCD memory + *unless* you define CONFIG_EXAMPLES_NXTEXT_NOGETRUN. If you notice + garbage on the display or a failure at the point where the display + should scroll, it is probably because you have an LCD driver that is + write-only. + + The following configuration options can be selected: + + CONFIG_EXAMPLES_NXTEXT_BUILTIN -- Build the NXTEXT example as a "built-in" + that can be executed from the NSH command line + CONFIG_EXAMPLES_NXTEXT_VPLANE -- The plane to select from the frame- + buffer driver for use in the test. Default: 0 + CONFIG_EXAMPLES_NXTEXT_DEVNO - The LCD device to select from the LCD + driver for use in the test: Default: 0 + CONFIG_EXAMPLES_NXTEXT_BGCOLOR -- The color of the background. Default + depends on CONFIG_EXAMPLES_NXTEXT_BPP. + CONFIG_EXAMPLES_NXTEXT_BGFONTID - Selects the font to use in the + background text (see font ID numbers in include/nuttx/nx/nxfonts.h) + CONFIG_EXAMPLES_NXTEXT_BGFONTCOLOR -- The color of the fonts used in the + background window. Default depends on CONFIG_EXAMPLES_NXTEXT_BPP. + CONFIG_EXAMPLES_NXTEXT_PUCOLOR -- The color of the pop-up window. Default + depends on CONFIG_EXAMPLES_NXTEXT_BPP. + CONFIG_EXAMPLES_NXTEXT_PUFONTID - Selects the font to use in the pop-up + windows (see font ID numbers in include/nuttx/nx/nxfonts.h) + CONFIG_EXAMPLES_NXTEXT_PUFONTCOLOR -- The color of the fonts used in the + background window. Default depends on CONFIG_EXAMPLES_NXTEXT_BPP. + CONFIG_EXAMPLES_NXTEXT_BPP -- Pixels per pixel to use. Valid options + include 2, 4, 8, 16, 24, and 32. Default is 32. + CONFIG_EXAMPLES_NXTEXT_NOGETRUN -- If your display is read-only OR if + reading is not reliable, then select this configuration to avoid + reading from the display. + CONFIG_EXAMPLES_NXTEXT_EXTERNINIT - The driver for the graphics device on + this platform requires some unusual initialization. This is the + for, for example, SPI LCD/OLED devices. If this configuration is + selected, then the platform code must provide an LCD initialization + function with a prototype like: + + #ifdef CONFIG_NX_LCDDRIVER + FAR struct lcd_dev_s *up_nxdrvinit(unsigned int devno); + #else + FAR struct fb_vtable_s *up_nxdrvinit(unsigned int devno); + #endif + + CONFIG_EXAMPLES_NXTEXT_BMCACHE - The maximum number of characters that + can be put in the background window. Default is 128. + CONFIG_EXAMPLES_NXTEXT_GLCACHE - The maximum nuber of pre-rendered + fonts that can be retained for the background window. + + This test can be performed with either the single-user version of + NX or with the multiple user version of NX selected with CONFIG_NX_MULTIUSER. + If CONFIG_NX_MULTIUSER is defined, then the following configuration + options also apply: + + CONFIG_EXAMPLES_NXTEXT_STACKSIZE -- The stacksize to use when creating + the NX server. Default 2048 + CONFIG_EXAMPLES_NXTEXT_CLIENTPRIO -- The client priority. Default: 100 + CONFIG_EXAMPLES_NXTEXT_SERVERPRIO -- The server priority. Default: 120 + CONFIG_EXAMPLES_NXTEXT_LISTENERPRIO -- The priority of the event listener + thread. Default 80. + CONFIG_EXAMPLES_NXTEXT_NOTIFYSIGNO -- The signal number to use with + nx_eventnotify(). Default: 4 + + If CONFIG_NX_MULTIUSER is defined, then the example also expects the + following settings and will generate an error if they are not as expected: + + CONFIG_DISABLE_MQUEUE=n + CONFIG_DISABLE_SIGNALS=n + CONFIG_DISABLE_PTHREAD=n + CONFIG_NX_BLOCKING=y + +examples/null +^^^^^^^^^^^^^ + + This is the do nothing application. It is only used for bringing + up new NuttX architectures in the most minimal of environments. + +examples/ostest +^^^^^^^^^^^^^^^ + + This is the NuttX 'qualification' suite. It attempts to exercise + a broad set of OS functionality. Its coverage is not very extensive + as of this writing, but it is used to qualify each NuttX release. + + The behavior of the ostest can be modified with the following + settings in the configs/<board-name>/defconfig file: + + * CONFIG_EXAMPLES_OSTEST_LOOPS + Used to control the number of executions of the test. If + undefined, the test executes one time. If defined to be + zero, the test runs forever. + * CONFIG_EXAMPLES_OSTEST_STACKSIZE + Used to create the ostest task. Default is 8192. + * CONFIG_EXAMPLES_OSTEST_NBARRIER_THREADS + Specifies the number of threads to create in the barrier + test. The default is 8 but a smaller number may be needed on + systems without sufficient memory to start so many threads. + +examples/pashello +^^^^^^^^^^^^^^^^^ + + This is "Hello, World" implemented via the Pascal P-Code interpreter. In + order to use this example, you must first download and install the + NuttX pascal module. After unpacking the pascal module, you can find + installation instructions in pascal/nuttx/README.txt. + + The correct install location for the NuttX examples and build files is + apps/interpreters. + +examples/pipe +^^^^^^^^^^^^^ + + A test of the mkfifo() and pipe() APIs. + + * CONFIG_EXAMPLES_PIPE_STACKSIZE + Sets the size of the stack to use when creating the child tasks. + The default size is 1024. + +examples/poll +^^^^^^^^^^^^^ + + A test of the poll() and select() APIs using FIFOs and, if available, + stdin, and a TCP/IP socket. In order to build this test, you must the + following selected in your NuttX configuration file: + + CONFIG_NFILE_DESCRIPTORS - Defined to be greater than 0 + CONFIG_DISABLE_POLL - NOT defined + + In order to use the TCP/IP select test, you have also the following + additional things selected in your NuttX configuration file: + + CONFIG_NET - Defined for general network support + CONFIG_NET_TCP - Defined for TCP/IP support + CONFIG_NSOCKET_DESCRIPTORS - Defined to be greater than 0 + CONFIG_NET_NTCP_READAHEAD_BUFFERS - Defined to be greater than zero + + CONFIG_EXAMPLE_POLL_NOMAC - (May be defined to use software assigned MAC) + CONFIG_EXAMPLE_POLL_IPADDR - Target IP address + CONFIG_EXAMPLE_POLL_DRIPADDR - Default router IP addess + CONFIG_EXAMPLE_POLL_NETMASK - Network mask + + In order to for select to work with incoming connections, you + must also select: + + CONFIG_NET_TCPBACKLOG - Incoming connections pend in a backlog until accept() is called. + + In additional to the target device-side example, there is also + a host-side application in this directory. It can be compiled under + Linux or Cygwin as follows: + + cd examples/usbserial + make -f Makefile.host TOPDIR=<nuttx-directory> TARGETIP=<target-ip> + + Where <target-ip> is the IP address of your target board. + + This will generate a small program called 'host'. Usage: + + 1. Build the examples/poll target program with TCP/IP poll support + and start the target. + + 3. Then start the host application: + + ./host + + The host and target will exchange are variety of small messages. Each + message sent from the host should cause the select to return in target. + The target example should read the small message and send it back to + the host. The host should then receive the echo'ed message. + + If networking is enabled, applications using this example will need to + provide an appconfig file in the configuration driver with instruction + to build applications like: + + CONFIGURED_APPS += uiplib + +examples/rgmp +^^^^^^^^^^^^^ + + RGMP stands for RTOS and GPOS on Multi-Processor. RGMP is a project for + running GPOS and RTOS simultaneously on multi-processor platforms. You can + port your favorite RTOS to RGMP together with an unmodified Linux to form a + hybrid operating system. This makes your application able to use both RTOS + and GPOS features. + + See http://rgmp.sourceforge.net/wiki/index.php/Main_Page for further + + At present, the RGMP example folder contains only an empty main.c file. + +examples/romfs +^^^^^^^^^^^^^^ + + This example exercises the romfs filesystem. Configuration options + include: + + * CONFIG_EXAMPLES_ROMFS_RAMDEVNO + The minor device number to use for the ROM disk. The default is + 1 (meaning /dev/ram1) + + * CONFIG_EXAMPLES_ROMFS_SECTORSIZE + The ROM disk sector size to use. Default is 64. + + * CONFIG_EXAMPLES_ROMFS_MOUNTPOINT + The location to mount the ROM disk. Deafault: "/usr/local/share" + +examples/sendmail +^^^^^^^^^^^^^^^^^ + + This examples exercises the uIP SMTP logic by sending a test message + to a selected recipient. This test can also be built to execute on + the Cygwin/Linux host environment: + + cd examples/sendmail + make -f Makefile.host TOPDIR=<nuttx-directory> + + Settings unique to this example include: + + CONFIG_EXAMPLE_SENDMAIL_NOMAC - May be defined to use software assigned MAC (optional) + CONFIG_EXAMPLE_SENDMAIL_IPADDR - Target IP address (required) + CONFIG_EXAMPLE_SENDMAIL_DRIPADDR - Default router IP addess (required) + CONFIG_EXAMPLE_SENDMAILT_NETMASK - Network mask (required) + CONFIG_EXAMPLE_SENDMAIL_RECIPIENT - The recipient of the email (required) + CONFIG_EXAMPLE_SENDMAIL_SENDER - Optional. Default: "nuttx-testing@example.com" + CONFIG_EXAMPLE_SENDMAIL_SUBJECT - Optional. Default: "Testing SMTP from NuttX" + CONFIG_EXAMPLE_SENDMAIL_BODY - Optional. Default: "Test message sent by NuttX" + + NOTE: This test has not been verified on the NuttX target environment. + As of this writing, unit-tested in the Cygwin/Linux host environment. + + NOTE 2: This sendmail example only works for the simplest of + environments. Virus protection software on your host may have + to be disabled to allow you to send messages. Only very open, + unprotected recipients can be used. Most will protect themselves + from this test email because it looks like SPAM. + + Applications using this example will need to provide an appconfig + file in the configuration driver with instruction to build applications + like: + + CONFIGURED_APPS += uiplib + CONFIGURED_APPS += smtp + +examples/serloop +^^^^^^^^^^^^^^^^ + + This is a mindlessly simple loopback test on the console. Useful + for testing new serial drivers. Configuration options include: + + * CONFIG_EXAMPLES_SERLOOP_BUFIO + Use C buffered I/O (getchar/putchar) vs. raw console I/O + (read/read). + +examples/thttpd +^^^^^^^^^^^^^^^ + + An example that builds netutils/thttpd with some simple NXFLAT + CGI programs. see configs/README.txt for most THTTPD settings. + In addition to those, this example accepts: + + CONFIG_EXAMPLE_THTTPD_NOMAC - (May be defined to use software assigned MAC) + CONFIG_EXAMPLE_THTTPD_DRIPADDR - Default router IP addess + CONFIG_EXAMPLE_THTTPD_NETMASK - Network mask + + Applications using this example will need to provide an appconfig + file in the configuration driver with instruction to build applications + like: + + CONFIGURED_APPS += uiplib + CONFIGURED_APPS += thttpd + +examples/tiff +^^^^^^^^^^^^^ + + This is a simple unit test for the TIFF creation library at apps/graphic/tiff. + It is configured to work in the Linux user-mode simulation and has not been + tested in any other environment. Since the example also depends on some + other logic to mount a file system, currently it will only work as an NSH + built-on, i.e., if the following is defined: + + CONFIG_NSH_BUILTIN_APPS=y + CONFIG_EXAMPLES_TIFF_BUILTIN=y + + At a miniumum, to run in an embedded environment, you will probably have to + change the configured paths to the TIFF files defined in the example. + + CONFIG_EXAMPLES_TIFF_OUTFILE - Name of the resulting TIFF file. Default is + "/tmp/result.tif" + CONFIG_EXAMPLES_TIFF_TMPFILE1/2 - Names of two temporaries files that + will be used in the file creation. Defaults are "/tmp/tmpfile1.dat" and + "/tmp/tmpfile2.dat" + + The following must also be defined in your apps/ configuration file: + + CONFIGURED_APPS += examples/tiff + CONFIGURED_APPS += graphics/tiff + +examples/touchscreen +^^^^^^^^^^^^^^^^^^^^ + + This configuration implements a simple touchscreen test at + apps/examples/touchscreen. This test will create an empty X11 window + and will print the touchscreen output as it is received from the + simulated touchscreen driver. + + CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN - Build the touchscreen test as + an NSH built-in function. Default: Built as a standalone problem + CONFIG_EXAMPLES_TOUCHSCREEN_MINOR - The minor device number. Minor=N + correspnds to touchscreen device /dev/input0. Note this value must + with CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH. Default 0. + CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH - The path to the touchscreen + device. This must be consistent with CONFIG_EXAMPLES_TOUCHSCREEN_MINOR. + Default: "/dev/input0" + CONFIG_EXAMPLES_TOUCHSCREEN_NSAMPLES - If CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN + is defined, then the number of samples is provided on the command line + and this value is ignored. Otherwise, this number of samples is + collected and the program terminates. Default: Samples are collected + indefinitely. + + The following additional configurations must be set in the NuttX + configuration file: + + CONFIG_INPUTP=y + (Plus any touchscreen-specific settings). + + The following must also be defined in your apps configuration file: + + CONFIGURED_APPS += examples/tiff + CONFIGURED_APPS += graphics/tiff + + The board-specific logic must provide the following interfaces that will + be called by the example in order to initialize and uninitialize the + touchscreen hardware: + + int arch_tcinitialize(int minor); + int arch_tcuninitialize(void); + +examples/udp +^^^^^^^^^^^^ + + This is a simple network test for verifying client- and server- + functionality over UDP. + + Applications using this example will need to provide an appconfig + file in the configuration driver with instruction to build applications + like: + + CONFIGURED_APPS += uiplib + +examples/uip +^^^^^^^^^^^^ + + This is a port of uIP tiny webserver example application. Settings + specific to this example include: + + CONFIG_EXAMPLE_UIP_NOMAC - (May be defined to use software assigned MAC) + CONFIG_EXAMPLE_UIP_IPADDR - Target IP address + CONFIG_EXAMPLE_UIP_DRIPADDR - Default router IP addess + CONFIG_EXAMPLE_UIP_NETMASK - Network mask + CONFIG_EXAMPLE_UIP_DHCPC - Select to get IP address via DHCP + + If you use DHCPC, then some special configuration network options are + required. These include: + + CONFIG_NET=y - Of course + CONFIG_NSOCKET_DESCRIPTORS - And, of course, you must allocate some + socket descriptors. + CONFIG_NET_UDP=y - UDP support is required for DHCP + (as well as various other UDP-related + configuration settings). + CONFIG_NET_BROADCAST=y - UDP broadcast support is needed. + CONFIG_NET_BUFSIZE=650 - Per RFC2131 (p. 9), the DHCP client must be + (or larger) prepared to receive DHCP messages of up to + 576 bytes (excluding Ethernet, IP, or UDP + headers and FCS). + + Other configuration items apply also to the selected webserver net utility. + Additional relevant settings for the uIP webserver net utility are: + + CONFIG_NETUTILS_HTTPDSTACKSIZE + CONFIG_NETUTILS_HTTPDFILESTATS + CONFIG_NETUTILS_HTTPDNETSTATS + + Applications using this example will need to provide an appconfig + file in the configuration driver with instruction to build applications + like: + + CONFIGURED_APPS += uiplib + CONFIGURED_APPS += dhcpc + CONFIGURED_APPS += resolv + CONFIGURED_APPS += webserver + +examples/usbserial +^^^^^^^^^^^^^^^^^^ + + TARGET CONFIGURATION: + + This is another implementation of "Hello, World" but this one uses + a USB serial driver. Configuration options can be used to simply + the test. These options include: + + CONFIG_EXAMPLES_USBSERIAL_INONLY + Only verify IN (device-to-host) data transfers. Default: both + CONFIG_EXAMPLES_USBSERIAL_OUTONLY + Only verify OUT (host-to-device) data transfers. Default: both + CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL + Send only small, single packet messages. Default: Send large and small. + CONFIG_EXAMPLES_USBSERIAL_ONLYBIG + Send only large, multi-packet messages. Default: Send large and small. + + If CONFIG_USBDEV_TRACE is enabled (or CONFIG_DEBUG and CONFIG_DEBUG_USB), then + the example code will also manage the USB trace output. The amount of trace output + can be controlled using: + + CONFIG_EXAMPLES_USBSERIAL_TRACEINIT + Show initialization events + CONFIG_EXAMPLES_USBSERIAL_TRACECLASS + Show class driver events + CONFIG_EXAMPLES_USBSERIAL_TRACETRANSFERS + Show data transfer events + CONFIG_EXAMPLES_USBSERIAL_TRACECONTROLLER + Show controller events + CONFIG_EXAMPLES_USBSERIAL_TRACEINTERRUPTS + Show interrupt-related events. + + Error results are always shown in the trace output + + HOST-SIDE TEST PROGRAM + + In additional to the target device-side example, there is also a + host-side application in this directory. This host side application + must be executed on a Linux host in order to perform the USBSERIAL + test. The host application can be compiled under Linux (or Cygwin?) + as follows: + + cd examples/usbserial + make -f Makefile.host TOPDIR=<nuttx-directory> + + RUNNING THE TEST + + This will generate a small program called 'host'. Usage: + + 1. Build the examples/usbserial target program and start the target. + + 2. Wait a bit, then do enter: + + dmesg + + At the end of the dmesg output, you should see the serial + device was successfully idenfied and assigned to a tty device, + probably /dev/ttyUSB0. + + 3. Then start the host application: + + ./host [<tty-dev>] + + Where: + + <tty-dev> is the USB TTY device to use. The default is /dev/ttyUSB0. + + The host and target will exchange are variety of very small and very large + serial messages. + +examples/usbstorage +^^^^^^^^^^^^^^^^^^^ + + This example registers a block device driver, then exports the block + the device using the USB storage class driver. In order to use this + example, your board-specific logic must provide the function: + + void usbstrg_archinitialize(void); + + This function will be called by the example/usbstorage in order to + do the actual registration of the block device drivers. For examples + of the implementation of usbstrg_archinitialize() see + configs/mcu123-lpc124x/src/up_usbstrg.c or + configs/stm3210e-eval/src/usbstrg.c + + Configuration options: + + CONFIG_EXAMPLES_USBSTRG_BUILTIN + This example can be built as two NSH "built-in" commands if this option + is selection: 'msconn' will connect the USB mass storage device; 'msdis' + will disconnect the USB storage device. + CONFIG_EXAMPLES_USBSTRG_NLUNS + Defines the number of logical units (LUNs) exported by the USB storage + driver. Each LUN corresponds to one exported block driver (or partition + of a block driver). May be 1, 2, or 3. Default is 1. + CONFIG_EXAMPLES_USBSTRG_DEVMINOR1 + The minor device number of the block driver for the first LUN. For + example, N in /dev/mmcsdN. Used for registering the block driver. Default + is zero. + CONFIG_EXAMPLES_USBSTRG_DEVPATH1 + The full path to the registered block driver. Default is "/dev/mmcsd0" + CONFIG_EXAMPLES_USBSTRG_DEVMINOR2 and CONFIG_EXAMPLES_USBSTRG_DEVPATH2 + Similar parameters that would have to be provided if CONFIG_EXAMPLES_USBSTRG_NLUNS + is 2 or 3. No defaults. + CONFIG_EXAMPLES_USBSTRG_DEVMINOR3 and CONFIG_EXAMPLES_USBSTRG_DEVPATH3 + Similar parameters that would have to be provided if CONFIG_EXAMPLES_USBSTRG_NLUNS + is 3. No defaults. + CONFIG_EXAMPLES_USBSTRG_DEBUGMM + Enables some debug tests to check for memory usage and memory leaks. + + If CONFIG_USBDEV_TRACE is enabled (or CONFIG_DEBUG and CONFIG_DEBUG_USB), then + the example code will also manage the USB trace output. The amount of trace output + can be controlled using: + + CONFIG_EXAMPLES_USBSTRG_TRACEINIT + Show initialization events + CONFIG_EXAMPLES_USBSTRG_TRACECLASS + Show class driver events + CONFIG_EXAMPLES_USBSTRG_TRACETRANSFERS + Show data transfer events + CONFIG_EXAMPLES_USBSTRG_TRACECONTROLLER + Show controller events + CONFIG_EXAMPLES_USBSTRG_TRACEINTERRUPTS + Show interrupt-related events. + + Error results are always shown in the trace output + + NOTE 1: When built as an NSH add-on command (CONFIG_EXAMPLES_USBSTRG_BUILTIN=y), + Caution should be used to assure that the SD drive (or other storage device) is + not in use when the USB storage device is configured. Specifically, the SD + driver should be unmounted like: + + nsh> mount -t vfat /dev/mmcsd0 /mnt/sdcard # Card is mounted in NSH + ... + nsh> umount /mnd/sdcard # Unmount before connecting USB!!! + nsh> msconn # Connect the USB storage device + ... + nsh> msdis # Disconnect USB storate device + nsh> mount -t vfat /dev/mmcsd0 /mnt/sdcard # Restore the mount + + Failure to do this could result in corruption of the SD card format. + + NOTE 2: This test exercises internal USB device driver interfaces. As such, + it relies on internal OS interfaces that are not normally available to a + user-space program. As a result, this example cannot be used if a + NuttX is built as a protected, supervisor kernel (CONFIG_NUTTX_KERNEL). + +examples/usbterm +^^^^^^^^^^^^^^^^ + + This example implements a little USB terminal.. more of a USB "chat" + edited lines are received from the remote host connected via USB + serial and echoed out the target serial console. Edited lines from + the local target serial console are received and forwarded to the + remote host via USB serial. + + Usage: + - Build the example and load into the target FLASH + - Connect on terminal to the target RS-232 connect and configure + for 115200 8N1. For example, suppose this Tera Term on a Windows + box. + - Power up the target board + - Connect the USB to a Linux box. Use the Linux dmesg command to + assure that the connect was successful. The USB CDC ACM device + should appear as /dev/ttyACM0 + - On the Linux box, open minicom with tty=/dev/ttyACM0. + Configure minicom so that (1) local characters are echoed and (2) + so that no CR is required. + - Now what you type on the target Tera Term window should echo on + the Linux minicom window and, conversely, what you type on the + minicom winow should be echo in the target Tera Term window. + + Configuration options: + + CONFIG_EXAMPLES_UBSTERM_BUILTIN - Build the usbterm example as an NSH + built-in command. NOTE: This is not fully functional as of this + writing.. It should work, but there is no mechanism in place yet + to exit the USB terminal program and return to NSH. + CONFIG_EXAMPLES_USBTERM_BUFLEN - The size of the input and output + buffers used for receiving data. Default 256 bytes. + + If CONFIG_USBDEV_TRACE is enabled (or CONFIG_DEBUG and CONFIG_DEBUG_USB, or + CONFIG_USBDEV_TRACE), then the example code will also manage the USB trace + output. The amount of trace output can be controlled using: + + CONFIG_EXAMPLES_USBTERM_TRACEINIT + Show initialization events + CONFIG_EXAMPLES_USBTERM_TRACECLASS + Show class driver events + CONFIG_EXAMPLES_USBTERM_TRACETRANSFERS + Show data transfer events + CONFIG_EXAMPLES_USBTERM_TRACECONTROLLER + Show controller events + CONFIG_EXAMPLES_USBTERM_TRACEINTERRUPTS + Show interrupt-related events. + + Error results are always shown in the trace output + + Other relevant configuration options: CONFIG_CDCSER selected by the + Prolifics emulation (not defined) and the CDC serial implementation + (when defined). CONFIG_USBDEV_TRACE_INITIALIDSET. + +examples/wget +^^^^^^^^^^^^^ + + A simple web client example. It will obtain a file from a server using the HTTP + protocol. Settings unique to this example include: + + CONFIG_EXAMPLE_WGET_URL - The URL of the file to get + CONFIG_EXAMPLE_WGET_NOMAC - (May be defined to use software assigned MAC) + CONFIG_EXAMPLE_WGET_IPADDR - Target IP address + CONFIG_EXAMPLE_WGET_DRIPADDR - Default router IP addess + CONFIG_EXAMPLE_WGET_NETMASK - Network mask + + This example uses netutils/webclient. Additional configuration settings apply + to that code as follows (but built-in defaults are probably OK): + + CONFIG_WEBCLIENT_GETMIMETYPE, CONFIG_WEBCLIENT_MAXHTTPLINE, + CONFIG_WEBCLIENT_MAXMIMESIZE, CONFIG_WEBCLIENT_MAXHOSTNAME, + CONFIG_WEBCLIENT_MAXFILENAME + + Of course, the example also requires other settings including CONFIG_NET and + CONFIG_NET_TCP. The example also uses the uIP resolver which requires CONFIG_UDP. + + WARNNG: As of this writing, wget is untested on the target platform. At present + it has been tested only in the host-based configuration described in the following + note. The primary difference is that the target version will rely on the also + untested uIP name resolver. + + NOTE: For test purposes, this example can be built as a host-based wget function. + This can be built as follows: + + cd examples/wget + make -f Makefile.host + + Applications using this example will need to provide an appconfig + file in the configuration driver with instruction to build applications + like: + + CONFIGURED_APPS += uiplib + CONFIGURED_APPS += resolv + CONFIGURED_APPS += webclient + + diff --git a/apps/examples/adc/Makefile b/apps/examples/adc/Makefile new file mode 100644 index 000000000..d9b2162e9 --- /dev/null +++ b/apps/examples/adc/Makefile @@ -0,0 +1,105 @@ +############################################################################ +# apps/examples/touchscreen/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttX NX Graphics Example. + +ASRCS = +CSRCS = adc_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Touchscreen built-in application info + +APPNAME = adc +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/adc/adc.h b/apps/examples/adc/adc.h new file mode 100755 index 000000000..901f84940 --- /dev/null +++ b/apps/examples/adc/adc.h @@ -0,0 +1,116 @@ +/**************************************************************************** + * examples/examples/adc.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_ADC_ADC_H +#define __APPS_EXAMPLES_ADC_ADC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* CONFIG_NSH_BUILTIN_APPS - Build the ADC test as an NSH built-in function. + * Default: Built as a standalone problem + * CONFIG_EXAMPLES_ADC_DEVPATH - The path to the ADC device. Default: /dev/adc0 + * CONFIG_EXAMPLES_ADC_NSAMPLES - If CONFIG_NSH_BUILTIN_APPS + * is defined, then the number of samples is provided on the command line + * and this value is ignored. Otherwise, this number of samples is + * collected and the program terminates. Default: Samples are collected + * indefinitely. + * CONFIG_EXAMPLES_ADC_GROUPSIZE - The number of samples to read at once. + * Default: 4 + */ + +#ifndef CONFIG_ADC +# error "ADC device support is not enabled (CONFIG_ADC)" +#endif + +#ifndef CONFIG_EXAMPLES_ADC_DEVPATH +# define CONFIG_EXAMPLES_ADC_DEVPATH "/dev/adc0" +#endif + +#ifndef CONFIG_EXAMPLES_ADC_GROUPSIZE +# define CONFIG_EXAMPLES_ADC_GROUPSIZE 4 +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_rawprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_rawprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: adc_devinit() + * + * Description: + * Perform architecuture-specific initialization of the ADC hardware. This + * interface must be provided by all configurations using apps/examples/adc + * + ****************************************************************************/ + +int adc_devinit(void); + +#endif /* __APPS_EXAMPLES_ADC_ADC_H */ diff --git a/apps/examples/adc/adc_main.c b/apps/examples/adc/adc_main.c new file mode 100644 index 000000000..e685f862d --- /dev/null +++ b/apps/examples/adc/adc_main.c @@ -0,0 +1,215 @@ +/**************************************************************************** + * examples/adc/adc_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/analog/adc.h> + +#include "adc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_NSH_BUILTIN_APPS +# define MAIN_NAME adc_main +# define MAIN_STRING "adc_main: " +#else +# define MAIN_NAME user_start +# define MAIN_STRING "user_start: " +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start/adc_main + ****************************************************************************/ + +int MAIN_NAME(int argc, char *argv[]) +{ + struct adc_msg_s sample[CONFIG_EXAMPLES_ADC_GROUPSIZE]; + size_t readsize; + ssize_t nbytes; +#if defined(CONFIG_NSH_BUILTIN_APPS) || defined(CONFIG_EXAMPLES_ADC_NSAMPLES) + long nsamples; +#endif + int fd; + int errval = 0; + int ret; + int i; + + /* If this example is configured as an NX add-on, then limit the number of + * samples that we collect before returning. Otherwise, we never return + */ + +#if defined(CONFIG_NSH_BUILTIN_APPS) + nsamples = 1; + if (argc > 1) + { + nsamples = strtol(argv[1], NULL, 10); + } + message(MAIN_STRING "nsamples: %d\n", nsamples); +#elif defined(CONFIG_EXAMPLES_ADC_NSAMPLES) + message(MAIN_STRING "nsamples: %d\n", CONFIG_EXAMPLES_ADC_NSAMPLES); +#endif + + /* Initialization of the ADC hardware is performed by logic external to + * this test. + */ + + message(MAIN_STRING "Initializing external ADC device\n"); + ret = adc_devinit(); + if (ret != OK) + { + message(MAIN_STRING "adc_devinit failed: %d\n", ret); + errval = 1; + goto errout; + } + message(MAIN_STRING "Hardware initialized. Opening the ADC device\n"); + + /* Open the ADC device for reading */ + + fd = open(CONFIG_EXAMPLES_ADC_DEVPATH, O_RDONLY); + if (fd < 0) + { + message(MAIN_STRING "open %s failed: %d\n", + CONFIG_EXAMPLES_ADC_DEVPATH, errno); + errval = 2; + goto errout_with_dev; + } + + /* Now loop the appropriate number of times, displaying the collected + * ADC samples. + */ + + message(MAIN_STRING "Entering the main loop\n"); + +#if defined(CONFIG_NSH_BUILTIN_APPS) + for (; nsamples > 0; nsamples--) +#elif defined(CONFIG_EXAMPLES_ADC_NSAMPLES) + for (nsamples = 0; nsamples < CONFIG_EXAMPLES_ADC_NSAMPLES; nsamples++) +#else + for (;;) +#endif + { + /* Flush any output before the loop entered or from the previous pass + * through the loop. + */ + + msgflush(); + + /* Read CONFIG_EXAMPLES_ADC_GROUPSIZE samples */ + + readsize = CONFIG_EXAMPLES_ADC_GROUPSIZE * sizeof(struct adc_msg_s); + nbytes = read(fd, sample, readsize); + message("Bytes read: %d\n", nbytes); + + /* Handle unexpected return values */ + + if (nbytes < 0) + { + errval = errno; + if (errval != EINTR) + { + message(MAIN_STRING "read %s failed: %d\n", + CONFIG_EXAMPLES_ADC_DEVPATH, errval); + errval = 3; + goto errout_with_dev; + } + + message(MAIN_STRING "Interrupted read...\n"); + } + else if (nbytes != readsize) + { + message(MAIN_STRING "Unexpected read size=%d, expected=%d, Ignoring\n", + nbytes, readsize); + } + + /* Print the sample data on successful return */ + + else + { + message("Sample :\n"); + for (i = 0; i < CONFIG_EXAMPLES_ADC_GROUPSIZE; i++) + { + message("%d: channel: %d value: %d\n", + i, sample[i].am_channel, sample[i].am_data); + } + } + } + +errout_with_dev: + close(fd); + +errout: + message("Terminating!\n"); + msgflush(); + return errval; +} diff --git a/apps/examples/buttons/Makefile b/apps/examples/buttons/Makefile new file mode 100644 index 000000000..9c0587199 --- /dev/null +++ b/apps/examples/buttons/Makefile @@ -0,0 +1,105 @@ +############################################################################ +# apps/examples/buttons/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Hello, World! Example + +ASRCS = +CSRCS = main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Buttons built-in application info + +APPNAME = buttons +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/buttons/main.c b/apps/examples/buttons/main.c new file mode 100644 index 000000000..b0d06e48a --- /dev/null +++ b/apps/examples/buttons/main.c @@ -0,0 +1,505 @@ +/**************************************************************************** + * examples/buttons/main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * NOTE: This test exercises internal button driver interfaces. As such, it + * it relies on internal OS interfaces that are not normally available to a + * user-space program. As a result, this example cannot be used if a + * NuttX is built as a protected, supervisor kernel (CONFIG_NUTTX_KERNEL). + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/arch.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <debug.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_ARCH_BUTTONS +# error "CONFIG_ARCH_BUTTONS is not defined in the configuration" +#endif + +#ifndef CONFIG_EXAMPLE_BUTTONS_NAME0 +# define CONFIG_EXAMPLE_BUTTONS_NAME0 "BUTTON0" +#endif +#ifndef CONFIG_EXAMPLE_BUTTONS_NAME1 +# define CONFIG_EXAMPLE_BUTTONS_NAME1 "BUTTON1" +#endif +#ifndef CONFIG_EXAMPLE_BUTTONS_NAME2 +# define CONFIG_EXAMPLE_BUTTONS_NAME2 "BUTTON2" +#endif +#ifndef CONFIG_EXAMPLE_BUTTONS_NAME3 +# define CONFIG_EXAMPLE_BUTTONS_NAME3 "BUTTON3" +#endif +#ifndef CONFIG_EXAMPLE_BUTTONS_NAME4 +# define CONFIG_EXAMPLE_BUTTONS_NAME4 "BUTTON4" +#endif +#ifndef CONFIG_EXAMPLE_BUTTONS_NAME5 +# define CONFIG_EXAMPLE_BUTTONS_NAME5 "BUTTON5" +#endif +#ifndef CONFIG_EXAMPLE_BUTTONS_NAME6 +# define CONFIG_EXAMPLE_BUTTONS_NAME6 "BUTTON6" +#endif +#ifndef CONFIG_EXAMPLE_BUTTONS_NAME7 +# define CONFIG_EXAMPLE_BUTTONS_NAME7 "BUTTON7" +#endif + +#define BUTTON_MIN 0 +#define BUTTON_MAX 7 + +#ifndef CONFIG_EXAMPLE_BUTTONS_MIN +# define CONFIG_EXAMPLE_BUTTONS_MIN BUTTON_MIN +#endif +#ifndef CONFIG_EXAMPLE_BUTTONS_MAX +# define CONFIG_EXAMPLE_BUTTONS_MAX BUTTON_MAX +#endif + +#if CONFIG_EXAMPLE_BUTTONS_MIN > CONFIG_EXAMPLE_BUTTONS_MAX +# error "CONFIG_EXAMPLE_BUTTONS_MIN > CONFIG_EXAMPLE_BUTTONS_MAX" +#endif +#if CONFIG_EXAMPLE_BUTTONS_MAX > 7 +# error "CONFIG_EXAMPLE_BUTTONS_MAX > 7" +#endif + +#ifndef CONFIG_EXAMPLE_IRQBUTTONS_MIN +# define CONFIG_EXAMPLE_IRQBUTTONS_MIN CONFIG_EXAMPLE_BUTTONS_MIN +#endif +#ifndef CONFIG_EXAMPLE_IRQBUTTONS_MAX +# define CONFIG_EXAMPLE_IRQBUTTONS_MAX CONFIG_EXAMPLE_BUTTONS_MAX +#endif + +#if CONFIG_EXAMPLE_IRQBUTTONS_MIN > CONFIG_EXAMPLE_IRQBUTTONS_MAX +# error "CONFIG_EXAMPLE_IRQBUTTONS_MIN > CONFIG_EXAMPLE_IRQBUTTONS_MAX" +#endif +#if CONFIG_EXAMPLE_IRQBUTTONS_MAX > 7 +# error "CONFIG_EXAMPLE_IRQBUTTONS_MAX > 7" +#endif + +#ifndef MIN +# define MIN(a,b) (a < b ? a : b) +#endif +#ifndef MAX +# define MAX(a,b) (a > b ? a : b) +#endif + +#define MIN_BUTTON MIN(CONFIG_EXAMPLE_BUTTONS_MIN, CONFIG_EXAMPLE_IRQBUTTONS_MIN) +#define MAX_BUTTON MAX(CONFIG_EXAMPLE_BUTTONS_MAX, CONFIG_EXAMPLE_IRQBUTTONS_MAX) + +#define NUM_BUTTONS (MAX_BUTTON - MIN_BUTTON + 1) +#define BUTTON_INDEX(b) ((b)-MIN_BUTTON) + +/* Is this being built as an NSH built-in application? */ + +#ifdef CONFIG_NSH_BUILTIN_APPS +# define MAIN_NAME buttons_main +# define MAIN_STRING "buttons_main: " +#else +# define MAIN_NAME user_start +# define MAIN_STRING "user_start: " +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct button_info_s +{ + FAR const char *name; /* Name for the button */ +#ifdef CONFIG_ARCH_IRQBUTTONS + xcpt_t handler; /* Button interrupt handler */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void show_buttons(uint8_t oldset, uint8_t newset); + +#ifdef CONFIG_ARCH_IRQBUTTONS +static void button_handler(int id, int irq); + +#if MIN_BUTTON < 1 +static int button0_handler(int irq, FAR void *context); +#endif +#if MIN_BUTTON < 2 && MAX_BUTTON > 0 +static int button1_handler(int irq, FAR void *context); +#endif +#if MIN_BUTTON < 3 && MAX_BUTTON > 1 +static int button2_handler(int irq, FAR void *context); +#endif +#if MIN_BUTTON < 4 && MAX_BUTTON > 2 +static int button3_handler(int irq, FAR void *context); +#endif +#if MIN_BUTTON < 5 && MAX_BUTTON > 3 +static int button4_handler(int irq, FAR void *context); +#endif +#if MIN_BUTTON < 6 && MAX_BUTTON > 4 +static int button5_handler(int irq, FAR void *context); +#endif +#if MIN_BUTTON < 7 && MAX_BUTTON > 5 +static int button6_handler(int irq, FAR void *context); +#endif +#if MAX_BUTTON > 6 +static int button7_handler(int irq, FAR void *context); +#endif +#endif /* CONFIG_ARCH_IRQBUTTONS */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + + /* Button Names */ + +static const struct button_info_s g_buttoninfo[NUM_BUTTONS] = +{ +#if MIN_BUTTON < 1 + { + CONFIG_EXAMPLE_BUTTONS_NAME0, +#ifdef CONFIG_ARCH_IRQBUTTONS + button0_handler +#endif + }, +#endif +#if MIN_BUTTON < 2 && MAX_BUTTON > 0 + { + CONFIG_EXAMPLE_BUTTONS_NAME1, +#ifdef CONFIG_ARCH_IRQBUTTONS + button1_handler +#endif + }, +#endif +#if MIN_BUTTON < 3 && MAX_BUTTON > 1 + { + CONFIG_EXAMPLE_BUTTONS_NAME2, +#ifdef CONFIG_ARCH_IRQBUTTONS + button2_handler +#endif + }, +#endif +#if MIN_BUTTON < 4 && MAX_BUTTON > 2 + { + CONFIG_EXAMPLE_BUTTONS_NAME3, +#ifdef CONFIG_ARCH_IRQBUTTONS + button3_handler +#endif + }, +#endif +#if MIN_BUTTON < 5 && MAX_BUTTON > 3 + { + CONFIG_EXAMPLE_BUTTONS_NAME4, +#ifdef CONFIG_ARCH_IRQBUTTONS + button4_handler +#endif + }, +#endif +#if MIN_BUTTON < 6 && MAX_BUTTON > 4 + { + CONFIG_EXAMPLE_BUTTONS_NAME5, +#ifdef CONFIG_ARCH_IRQBUTTONS + button5_handler +#endif + }, +#endif +#if MIN_BUTTON < 7 && MAX_BUTTON > 5 + { + CONFIG_EXAMPLE_BUTTONS_NAME6, +#ifdef CONFIG_ARCH_IRQBUTTONS + button6_handler +#endif + }, +#endif +#if MAX_BUTTON > 6 + { + CONFIG_EXAMPLE_BUTTONS_NAME7, +#ifdef CONFIG_ARCH_IRQBUTTONS + button7_handler +#endif + } +#endif +}; + +/* Last sampled button set */ + +static uint8_t g_oldset; + +/* Used to limit the number of button presses */ + +#ifdef CONFIG_NSH_BUILTIN_APPS +static volatile long g_nbuttons; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void show_buttons(uint8_t oldset, uint8_t newset) +{ + uint8_t chgset = oldset ^ newset; + int i; + + /* Update the count of button presses shown */ + +#ifdef CONFIG_NSH_BUILTIN_APPS + if ((chgset & newset) != 0) + { + g_nbuttons++; + } +#endif + + /* Show each button state change */ + + for (i = MIN_BUTTON; i <= MAX_BUTTON; i++) + { + uint8_t mask = (1 << i); + if ((chgset & mask) != 0) + { + FAR const char *state; + + /* Get the button state */ + + if ((newset & mask) != 0) + { + state = "depressed"; + } + else + { + state = "released"; + } + + /* Use lib_lowprintf() because we make be executing from an + * interrupt handler. + */ + + lib_lowprintf(" %s %s\n", g_buttoninfo[BUTTON_INDEX(i)].name, state); + } + } +} + +#ifdef CONFIG_ARCH_IRQBUTTONS +static void button_handler(int id, int irq) +{ + uint8_t newset = up_buttons(); + + lib_lowprintf("IRQ:%d Button %d:%s SET:%02x:\n", + irq, id, g_buttoninfo[BUTTON_INDEX(id)].name, newset); + show_buttons(g_oldset, newset); + g_oldset = newset; +} + +#if MIN_BUTTON < 1 +static int button0_handler(int irq, FAR void *context) +{ + button_handler(0, irq); + return OK; +} +#endif + +#if MIN_BUTTON < 2 && MAX_BUTTON > 0 +static int button1_handler(int irq, FAR void *context) +{ + button_handler(1, irq); + return OK; +} +#endif + +#if MIN_BUTTON < 3 && MAX_BUTTON > 1 +static int button2_handler(int irq, FAR void *context) +{ + button_handler(2, irq); + return OK; +} +#endif + +#if MIN_BUTTON < 4 && MAX_BUTTON > 2 +static int button3_handler(int irq, FAR void *context) +{ + button_handler(3, irq); + return OK; +} +#endif + +#if MIN_BUTTON < 5 && MAX_BUTTON > 3 +static int button4_handler(int irq, FAR void *context) +{ + button_handler(4, irq); + return OK; +} +#endif + +#if MIN_BUTTON < 6 && MAX_BUTTON > 4 +static int button5_handler(int irq, FAR void *context) +{ + button_handler(5, irq); + return OK; +} +#endif + +#if MIN_BUTTON < 7 && MAX_BUTTON > 5 +static int button6_handler(int irq, FAR void *context) +{ + button_handler(6, irq); + return OK; +} +#endif + +#if MAX_BUTTON > 6 +static int button7_handler(int irq, FAR void *context) +{ + button_handler(7, irq); + return OK; +} +#endif +#endif /* CONFIG_ARCH_IRQBUTTONS */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start/buttons_main + ****************************************************************************/ + +int MAIN_NAME(int argc, char *argv[]) +{ + uint8_t newset; + irqstate_t flags; + int i; + + /* If this example is configured as an NX add-on, then limit the number of + * samples that we collect before returning. Otherwise, we never return + */ + +#ifdef CONFIG_NSH_BUILTIN_APPS + long maxbuttons = 1; + g_nbuttons = 0; + if (argc > 1) + { + maxbuttons = strtol(argv[1], NULL, 10); + } + lib_lowprintf("maxbuttons: %d\n", maxbuttons); +#endif + + /* Register to recieve button interrupts */ + +#ifdef CONFIG_ARCH_IRQBUTTONS + for (i = CONFIG_EXAMPLE_IRQBUTTONS_MIN; i <= CONFIG_EXAMPLE_IRQBUTTONS_MAX; i++) + { + xcpt_t oldhandler = up_irqbutton(i, g_buttoninfo[BUTTON_INDEX(i)].handler); + + /* Use lib_lowprintf() for compatibility with interrrupt handler output. */ + + lib_lowprintf("Attached handler at %p to button %d [%s], oldhandler:%p\n", + g_buttoninfo[BUTTON_INDEX(i)].handler, i, + g_buttoninfo[BUTTON_INDEX(i)].name, oldhandler); + + /* Some hardware multiplexes different GPIO button sources to the same + * physical interrupt. If we register multiple such multiplexed button + * interrupts, then the second registration will overwrite the first. In + * this case, the first button interrupts may be aliased to the second + * interrupt handler (or worse, could be lost). + */ + + if (oldhandler != NULL) + { + lib_lowprintf("WARNING: oldhandler:%p is not NULL! " + "Button events may be lost or aliased!\n", + oldhandler); + } + } +#endif + + /* Poll button state */ + + g_oldset = up_buttons(); +#ifdef CONFIG_NSH_BUILTIN_APPS + while (g_nbuttons < maxbuttons) +#else + for (;;) +#endif + { + /* Get the set of pressed and release buttons. */ + + newset = up_buttons(); + + /* Any changes from the last sample? */ + + if (newset != g_oldset) + { + /* Disable interrupts so that output here will not collide with + * output from an interrupt handler. + */ + + flags = irqsave(); + + /* Use lib_lowprintf() for compatibility with interrrupt handler + * output. + */ + + lib_lowprintf("POLL SET:%02x:\n", newset); + show_buttons(g_oldset, newset); + g_oldset = newset; + irqrestore(flags); + } + + /* Sleep a little... but not long. This will determine how fast we + * poll for button changes. + */ + + usleep(150000); /* 150 Milliseconds */ + } + + /* Un-register button handlers */ + +#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NSH_BUILTIN_APPS) + for (i = CONFIG_EXAMPLE_IRQBUTTONS_MIN; i <= CONFIG_EXAMPLE_IRQBUTTONS_MAX; i++) + { + (void)up_irqbutton(i, NULL); + } +#endif + + return 0; +} + diff --git a/apps/examples/dhcpd/Makefile b/apps/examples/dhcpd/Makefile new file mode 100644 index 000000000..3254a9806 --- /dev/null +++ b/apps/examples/dhcpd/Makefile @@ -0,0 +1,106 @@ +############################################################################ +# apps/examples/dhcpd/Makefile +# +# Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# DHCP Daemon Example + +ASRCS = +CSRCS = target.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# DHCPD built-in application info + +APPNAME = dhcpd +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/dhcpd/Makefile.host b/apps/examples/dhcpd/Makefile.host new file mode 100644 index 000000000..19af5f42f --- /dev/null +++ b/apps/examples/dhcpd/Makefile.host @@ -0,0 +1,62 @@ +############################################################################ +# apps/examples/dhcpd/Makefile.host +# +# Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TOPDIR must be defined on the make command line + +include $(TOPDIR)/Make.defs + +OBJS = host.o1 dhcpd.o1 +BIN = dhcpd + +HOSTCFLAGS += -DCONFIG_NETUTILS_DHCPD_HOST=1 +HOSTCFLAGS += -DCONFIG_NETUTILS_DHCPD_INTERFACE=\"eth1\" +HOSTCFLAGS += -DHAVE_SO_REUSEADDR=1 +HOSTCFLAGS += -DHAVE_SO_BROADCAST=1 + +VPATH = $(TOPDIR)/netutils/dhcpd:. + +all: $(BIN) +.PHONY: clean context clean_context distclean + +$(OBJS): %.o1: %.c + $(HOSTCC) -c $(HOSTCFLAGS) $< -o $@ + +$(BIN): $(OBJS) + $(HOSTCC) $(HOSTLDFLAGS) $^ -o $@ + +clean: + @rm -f $(BIN).* *.o1 *~ + + diff --git a/apps/examples/dhcpd/host.c b/apps/examples/dhcpd/host.c new file mode 100644 index 000000000..479a845c1 --- /dev/null +++ b/apps/examples/dhcpd/host.c @@ -0,0 +1,58 @@ +/**************************************************************************** + * examples/dhcpd/host.c + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +extern int dhcpd_run(void); + +/**************************************************************************** + * main + ****************************************************************************/ + +int main(int argc, char **argv, char **envp) +{ + dhcpd_run(); + return 0; +} diff --git a/apps/examples/dhcpd/target.c b/apps/examples/dhcpd/target.c new file mode 100644 index 000000000..350bfe15f --- /dev/null +++ b/apps/examples/dhcpd/target.c @@ -0,0 +1,142 @@ +/**************************************************************************** + * examples/dhcpd/target.c + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> + +#include <apps/netutils/uiplib.h> +#include <apps/netutils/dhcpd.h> + +/**************************************************************************** + * Preprocessor Definitions + ****************************************************************************/ + +/* Configuation Checkes *****************************************************/ +/* BEWARE: + * There are other configuration settings needed in netutils/dhcpd/dhcpdc.c, + * but there are default values for those so we cannot check them here. + */ + +#ifndef CONFIG_EXAMPLE_DHCPD_IPADDR +# error "You must define CONFIG_EXAMPLE_DHCPD_IPADDR" +#endif + +#ifndef CONFIG_EXAMPLE_DHCPD_DRIPADDR +# error "You must define CONFIG_EXAMPLE_DHCPD_DRIPADDR" +#endif + +#ifndef CONFIG_EXAMPLE_DHCPD_NETMASK +# error "You must define CONFIG_EXAMPLE_DHCPD_NETMASK" +#endif + +#ifndef CONFIG_NET +# error "You must define CONFIG_NET" +#endif + +#ifndef CONFIG_NET_UDP +# error "You must define CONFIG_NET_UDP" +#endif + +#ifndef CONFIG_NET_BROADCAST +# error "You must define CONFIG_NET_BROADCAST" +#endif + +/* If CONFIG_NSH_BUILTIN_APPS is defined, then it is assumed that you want + * to execute the DHCPD daemon as an NSH built-in task. + */ + +#ifdef CONFIG_NSH_BUILTIN_APPS +# define MAIN_NAME dhcpd_main +# define MAIN_NAME_STRING "dhcpd_main" +#else +# define MAIN_NAME user_start +# define MAIN_NAME_STRING "user_start" +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start/dhcpd_main + ****************************************************************************/ + +int MAIN_NAME(int argc, char *argv[]) +{ + struct in_addr addr; +#if defined(CONFIG_EXAMPLE_DHCPD_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif + +/* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_DHCPD_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_DHCPD_IPADDR); + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_DHCPD_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_DHCPD_NETMASK); + uip_setnetmask("eth0", &addr); + + /* Then start the server */ + + dhcpd_run(); + return 0; +} diff --git a/apps/examples/ftpc/Makefile b/apps/examples/ftpc/Makefile new file mode 100644 index 000000000..ff2ec543b --- /dev/null +++ b/apps/examples/ftpc/Makefile @@ -0,0 +1,105 @@ +############################################################################ +# apps/examples/ftpc/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# FTPC Client Application + +APPNAME = ftpc +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 4096 + +ASRCS = +CSRCS = ftpc_main.c ftpc_cmds.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +# Register application + +.context: + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ + +context: .context + +# Create dependencies + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f .context Make.dep .depend + +-include Make.dep diff --git a/apps/examples/ftpc/ftpc.h b/apps/examples/ftpc/ftpc.h new file mode 100644 index 000000000..b6fe35aed --- /dev/null +++ b/apps/examples/ftpc/ftpc.h @@ -0,0 +1,112 @@ +/**************************************************************************** + * apps/examples/ftpc/ftpc.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_FTPC_FTPC_H +#define __APPS_EXAMPLES_FTPC_FTPC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> + +#include <apps/ftpc.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Maximum size of one command line */ + +#ifndef CONFIG_FTPC_LINELEN +# define CONFIG_FTPC_LINELEN 80 +#endif + +/* If CONFIG_STDIO_LINEBUFFER is defined, the STDIO buffer will be flushed + * on each new line. Otherwise, STDIO needs to be explicitly flushed to + * see the output in context. + */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && \ + CONFIG_STDIO_BUFFER_SIZE > 0 && !defined(CONFIG_STDIO_LINEBUFFER) +# define FFLUSH() fflush(stdout) +#else +# define FFLUSH() +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef int (*cmd_t)(SESSION handle, int argc, char **argv); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* FTP command handlers */ + +extern int cmd_rlogin(SESSION handle, int argc, char **argv); +extern int cmd_rquit(SESSION handle, int argc, char **argv); +extern int cmd_rchdir(SESSION handle, int argc, char **argv); +extern int cmd_rpwd(SESSION handle, int argc, char **argv); +extern int cmd_rcdup(SESSION handle, int argc, char **argv); +extern int cmd_rmkdir(SESSION handle, int argc, char **argv); + +extern int cmd_rrmdir(SESSION handle, int argc, char **argv); +extern int cmd_runlink(SESSION handle, int argc, char **argv); +extern int cmd_rchmod(SESSION handle, int argc, char **argv); +extern int cmd_rrename(SESSION handle, int argc, char **argv); +extern int cmd_rsize(SESSION handle, int argc, char **argv); +extern int cmd_rtime(SESSION handle, int argc, char **argv); +extern int cmd_ridle(SESSION handle, int argc, char **argv); +extern int cmd_rnoop(SESSION handle, int argc, char **argv); +extern int cmd_rhelp(SESSION handle, int argc, char **argv); +extern int cmd_rls(SESSION handle, int argc, char **argv); +extern int cmd_rget(SESSION handle, int argc, char **argv); +extern int cmd_rput(SESSION handle, int argc, char **argv); + +#endif /* __APPS_EXAMPLES_FTPC_FTPC_H */ diff --git a/apps/examples/ftpc/ftpc_cmds.c b/apps/examples/ftpc/ftpc_cmds.c new file mode 100755 index 000000000..f95f643cb --- /dev/null +++ b/apps/examples/ftpc/ftpc_cmds.c @@ -0,0 +1,398 @@ +/**************************************************************************** + * examples/ftpc/ftpc_cmds.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <apps/ftpc.h> + +#include "ftpc.h" + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_rlogin + ****************************************************************************/ + +int cmd_rlogin(SESSION handle, int argc, char **argv) +{ + struct ftpc_login_s login = {NULL, NULL, NULL, true}; + + login.uname = argv[1]; + if (argc > 2) + { + login.pwd = argv[2]; + } + + return ftpc_login(handle, &login); +} + +/**************************************************************************** + * Name: cmd_rquit + ****************************************************************************/ + +int cmd_rquit(SESSION handle, int argc, char **argv) +{ + int ret = ftpc_quit(handle); + if (ret < 0) + { + printf("quit failed: %d\n", errno); + } + printf("Exitting...\n"); + exit(0); + return ERROR; +} + +/**************************************************************************** + * Name: cmd_rchdir + ****************************************************************************/ + +int cmd_rchdir(SESSION handle, int argc, char **argv) +{ + return ftpc_chdir(handle, argv[1]); +} + +/**************************************************************************** + * Name: cmd_rpwd + ****************************************************************************/ + +int cmd_rpwd(SESSION handle, int argc, char **argv) +{ + FAR char *pwd = ftpc_rpwd(handle); + if (pwd) + { + printf("PWD: %s\n", pwd); + free(pwd); + return OK; + } + return ERROR; +} + +/**************************************************************************** + * Name: cmd_rcdup + ****************************************************************************/ + +int cmd_rcdup(SESSION handle, int argc, char **argv) +{ + return ftpc_cdup(handle); +} + +/**************************************************************************** + * Name: cmd_rmkdir + ****************************************************************************/ + +int cmd_rmkdir(SESSION handle, int argc, char **argv) +{ + return ftpc_mkdir(handle, argv[1]); +} + +/**************************************************************************** + * Name: cmd_rrmdir + ****************************************************************************/ + +int cmd_rrmdir(SESSION handle, int argc, char **argv) +{ + return ftpc_rmdir(handle, argv[1]); +} + +/**************************************************************************** + * Name: cmd_runlink + ****************************************************************************/ + +int cmd_runlink(SESSION handle, int argc, char **argv) +{ + return ftpc_unlink(handle, argv[1]); +} + +/**************************************************************************** + * Name: cmd_rchmod + ****************************************************************************/ + +int cmd_rchmod(SESSION handle, int argc, char **argv) +{ + return ftpc_chmod(handle, argv[1], argv[2]); +} + +/**************************************************************************** + * Name: cmd_rrename + ****************************************************************************/ + +int cmd_rrename(SESSION handle, int argc, char **argv) +{ + return ftpc_rename(handle, argv[1], argv[2]); +} + +/**************************************************************************** + * Name: cmd_rsize + ****************************************************************************/ + +int cmd_rsize(SESSION handle, int argc, char **argv) +{ + off_t size = ftpc_filesize(handle, argv[1]); + printf("SIZE: %lu\n", size); + return OK; +} + +/**************************************************************************** + * Name: cmd_rtime + ****************************************************************************/ + +int cmd_rtime(SESSION handle, int argc, char **argv) +{ + time_t filetime = ftpc_filetime(handle, argv[1]); + printf("TIME: %lu\n", (long)filetime); + return OK; +} + +/**************************************************************************** + * Name: cmd_ridle + ****************************************************************************/ + +int cmd_ridle(SESSION handle, int argc, char **argv) +{ + unsigned int idletime = 0; + + if (argc > 1) + { + idletime = atoi(argv[1]); + } + + return ftpc_idle(handle, idletime); +} + +/**************************************************************************** + * Name: cmd_rnoop + ****************************************************************************/ + +int cmd_rnoop(SESSION handle, int argc, char **argv) +{ + return ftpc_noop(handle); +} + +/**************************************************************************** + * Name: cmd_rhelp + ****************************************************************************/ + +int cmd_rhelp(SESSION handle, int argc, char **argv) +{ + FAR const char *cmd = NULL; + int ret; + + if (argc > 1) + { + cmd = argv[1]; + } + + ret = ftpc_help(handle, cmd); + if (ret == OK) + { + FAR char *msg = ftpc_response(handle); + puts(msg); + free(msg); + } + + return ret; +} + +/**************************************************************************** + * Name: cmd_rls + ****************************************************************************/ + +int cmd_rls(SESSION handle, int argc, char **argv) +{ + FAR struct ftpc_dirlist_s *dirlist; + FAR char *dirname = NULL; + int i; + + /* Get the directory listing */ + + if (argc > 1) + { + dirname = argv[1]; + } + + dirlist = ftpc_listdir(handle, dirname); + if (!dirlist) + { + return ERROR; + } + + /* Print the directory listing */ + + printf("%s/\n", dirname ? dirname : "."); + for (i = 0; i < dirlist->nnames; i++) + { + printf(" %s\n", dirlist->name[i]); + } + FFLUSH(); + + /* We are responsible for freeing the directory structure allocated by + * ftpc_listdir(). + */ + + ftpc_dirfree(dirlist); + return OK; +} + +/**************************************************************************** + * Name: cmd_rget + ****************************************************************************/ + +int cmd_rget(SESSION handle, int argc, char **argv) +{ + FAR const char *rname; + FAR const char *lname = NULL; + int xfrmode = FTPC_XFRMODE_ASCII; + int option; + + while ((option = getopt(argc, argv, "ab")) != ERROR) + { + if (option == 'a') + { + xfrmode = FTPC_XFRMODE_ASCII; + } + else if (option == 'b') + { + xfrmode = FTPC_XFRMODE_BINARY; + } + else + { + printf("%s: Unrecognized option: '%c'\n", "put", option); + return ERROR; + } + } + + /* There should be one or two parameters remaining on the command line */ + + if (optind >= argc) + { + printf("%s: Missing required arguments\n", "get"); + return ERROR; + } + + rname = argv[optind]; + optind++; + + if (optind < argc) + { + lname = argv[optind]; + optind++; + } + + if (optind != argc) + { + printf("%s: Too many arguments\n", "get"); + return ERROR; + } + + /* Perform the transfer */ + + return ftpc_getfile(handle, rname, lname, FTPC_GET_NORMAL, xfrmode); +} + +/**************************************************************************** + * Name: cmd_rput + ****************************************************************************/ + +int cmd_rput(SESSION handle, int argc, char **argv) +{ + FAR const char *lname; + FAR const char *rname = NULL; + int xfrmode = FTPC_XFRMODE_ASCII; + int option; + + while ((option = getopt(argc, argv, "ab")) != ERROR) + { + if (option == 'a') + { + xfrmode = FTPC_XFRMODE_ASCII; + } + else if (option == 'b') + { + xfrmode = FTPC_XFRMODE_BINARY; + } + else + { + printf("%s: Unrecognized option: '%c'\n", "put", option); + return ERROR; + } + } + + /* There should be one or two parameters remaining on the command line */ + + if (optind >= argc) + { + printf("%s: Missing required arguments\n", "get"); + return ERROR; + } + + lname = argv[optind]; + optind++; + + if (optind < argc) + { + rname = argv[optind]; + optind++; + } + + if (optind != argc) + { + printf("%s: Too many arguments\n "); + return ERROR; + } + + /* Perform the transfer */ + + return ftp_putfile(handle, lname, rname, FTPC_PUT_NORMAL, xfrmode); +} diff --git a/apps/examples/ftpc/ftpc_main.c b/apps/examples/ftpc/ftpc_main.c new file mode 100755 index 000000000..7a1cb50f7 --- /dev/null +++ b/apps/examples/ftpc/ftpc_main.c @@ -0,0 +1,426 @@ +/**************************************************************************** + * examples/ftpc/ftpc_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <arpa/inet.h> +#include <apps/ftpc.h> + +#include "ftpc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define FTPC_MAX_ARGUMENTS 4 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct cmdmap_s +{ + const char *cmd; /* Name of the command */ + cmd_t handler; /* Function that handles the command */ + uint8_t minargs; /* Minimum number of arguments (including command) */ + uint8_t maxargs; /* Maximum number of arguments (including command) */ + const char *usage; /* Usage instructions for 'help' command */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_delim[] = " \t\n"; + +static int cmd_lhelp(SESSION handle, int argc, char **argv); +static int cmd_lunrecognized(SESSION handle, int argc, char **argv); + +static const struct cmdmap_s g_cmdmap[] = +{ + { "cd", cmd_rchdir, 2, 2, "<directory>" }, + { "chmod", cmd_rchmod, 3, 3, "<permissions> <path>" }, + { "get", cmd_rget, 2, 4, "[-a|b] <rname> [<lname>]" }, + { "help", cmd_lhelp, 1, 2, "" }, + { "idle", cmd_ridle, 1, 2, "[<idletime>]" }, + { "login", cmd_rlogin, 2, 3, "<uname> [<password>]" }, + { "ls", cmd_rls, 1, 2, "[<dirpath>]" }, + { "quit", cmd_rquit, 1, 1, "" }, + { "mkdir", cmd_rmkdir, 2, 2, "<directory>" }, + { "noop", cmd_rnoop, 1, 1, "" }, + { "put", cmd_rput, 2, 4, "[-a|b] <lname> [<rname>]" }, + { "pwd", cmd_rpwd, 1, 1, "" }, + { "rename", cmd_rrename, 3, 3, "<oldname> <newname>" }, + { "rhelp", cmd_rhelp, 1, 2, "[<command>]" }, + { "rm", cmd_runlink, 2, 2, "" }, + { "rmdir", cmd_rrmdir, 2, 2, "<directory>" }, + { "size", cmd_rsize, 2, 2, "<filepath>" }, + { "time", cmd_rtime, 2, 2, "<filepath>" }, + { "up", cmd_rcdup, 1, 1, "" }, + { NULL, NULL, 1, 1, NULL } +}; + +static char g_line[CONFIG_FTPC_LINELEN]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_lhelp + ****************************************************************************/ + +static int cmd_lhelp(SESSION handle, int argc, char **argv) +{ + const struct cmdmap_s *ptr; + + printf("Local FTPC commands:\n"); + for (ptr = g_cmdmap; ptr->cmd; ptr++) + { + if (ptr->usage) + { + printf(" %s %s\n", ptr->cmd, ptr->usage); + } + else + { + printf(" %s\n", ptr->cmd); + } + } + return OK; +} + +/**************************************************************************** + * Name: cmd_lunrecognized + ****************************************************************************/ + +static int cmd_lunrecognized(SESSION handle, int argc, char **argv) +{ + printf("Command %s unrecognized\n", argv[0]); + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_argument + ****************************************************************************/ + +char *ftpc_argument(char **saveptr) +{ + char *pbegin = *saveptr; + char *pend = NULL; + const char *term; + + /* Find the beginning of the next token */ + + for (; + *pbegin && strchr(g_delim, *pbegin) != NULL; + pbegin++); + + /* If we are at the end of the string with nothing + * but delimiters found, then return NULL. + */ + + if (!*pbegin) + { + return NULL; + } + + /* Does the token begin with '#' -- comment */ + + else if (*pbegin == '#') + { + /* Return NULL meaning that we are at the end of the line */ + + *saveptr = pbegin; + pbegin = NULL; + } + else + { + /* Otherwise, we are going to have to parse to find the end of + * the token. Does the token begin with '"'? + */ + + if (*pbegin == '"') + { + /* Yes.. then only another '"' can terminate the string */ + + pbegin++; + term = "\""; + } + else + { + /* No, then any of the usual terminators will terminate the argument */ + + term = g_delim; + } + + /* Find the end of the string */ + + for (pend = pbegin + 1; + *pend && strchr(term, *pend) == NULL; + pend++); + + /* pend either points to the end of the string or to + * the first delimiter after the string. + */ + + if (*pend) + { + /* Turn the delimiter into a null terminator */ + + *pend++ = '\0'; + } + + /* Save the pointer where we left off */ + + *saveptr = pend; + + } + + /* Return the beginning of the token. */ + + return pbegin; +} + +/**************************************************************************** + * Name: ftpc_execute + ****************************************************************************/ + +static int ftpc_execute(SESSION handle, int argc, char *argv[]) +{ + const struct cmdmap_s *cmdmap; + const char *cmd; + cmd_t handler = cmd_lunrecognized; + int ret; + + /* The form of argv is: + * + * argv[0]: The command name. This is argv[0] when the arguments + * are, finally, received by the command handler + * argv[1]: The beginning of argument (up to FTPC_MAX_ARGUMENTS) + * argv[argc]: NULL terminating pointer + */ + + cmd = argv[0]; + + /* See if the command is one that we understand */ + + for (cmdmap = g_cmdmap; cmdmap->cmd; cmdmap++) + { + if (strcmp(cmdmap->cmd, cmd) == 0) + { + /* Check if a valid number of arguments was provided. We + * do this simple, imperfect checking here so that it does + * not have to be performed in each command. + */ + + if (argc < cmdmap->minargs) + { + /* Fewer than the minimum number were provided */ + + printf("Too few arguments for '%s'\n", cmd); + return ERROR; + } + else if (argc > cmdmap->maxargs) + { + /* More than the maximum number were provided */ + + printf("Too many arguments for '%s'\n", cmd); + return ERROR; + } + else + { + /* A valid number of arguments were provided (this does + * not mean they are right). + */ + + handler = cmdmap->handler; + break; + } + } + } + + ret = handler(handle, argc, argv); + if (ret < 0) + { + printf("%s failed: %d\n", cmd, errno); + } + return ret; +} + +/**************************************************************************** + * Name: ftpc_parse + ****************************************************************************/ + +int ftpc_parse(SESSION handle, char *cmdline) +{ + FAR char *argv[FTPC_MAX_ARGUMENTS]; + FAR char *saveptr; + FAR char *cmd; + int argc; + int ret; + + /* Initialize parser state */ + + memset(argv, 0, FTPC_MAX_ARGUMENTS*sizeof(FAR char *)); + + /* Parse out the command at the beginning of the line */ + + saveptr = cmdline; + cmd = ftpc_argument(&saveptr); + + /* Check if any command was provided -OR- if command processing is + * currently disabled. + */ + + if (!cmd) + { + /* An empty line is not an error */ + + return OK; + } + + /* Parse all of the arguments following the command name. */ + + argv[0] = cmd; + for (argc = 1; argc < FTPC_MAX_ARGUMENTS; argc++) + { + argv[argc] = ftpc_argument(&saveptr); + if (!argv[argc]) + { + break; + } + } + argv[argc] = NULL; + + /* Check if the maximum number of arguments was exceeded */ + + if (argc > FTPC_MAX_ARGUMENTS) + { + printf("Too many arguments\n"); + ret = -EINVAL; + } + else + { + /* Then execute the command */ + + ret = ftpc_execute(handle, argc, argv); + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int ftpc_main(int argc, char **argv, char **envp) +{ + struct ftpc_connect_s connect = {{0}, 0}; + SESSION handle; + FAR char *ptr; + + if (argc != 2) + { + printf("Usage:\n"); + printf(" %s xx.xx.xx.xx[:pp]\n", argv[0]); + printf("Where\n"); + printf(" xx.xx.xx.xx is the IP address of the FTP server\n"); + printf(" pp is option port to use with the FTP server\n"); + exit(1); + } + + /* Check if the argument includes a port number */ + + ptr = strchr(argv[1], ':'); + if (ptr) + { + *ptr = '\0'; + connect.port = atoi(ptr+1); + } + + /* In any event, we can now extract the IP address from the comman-line */ + + connect.addr.s_addr = inet_addr(argv[1]); + + /* Connect to the FTP server */ + + handle = ftpc_connect(&connect); + if (!handle) + { + printf("Failed to connect to the server: %d\n", errno); + exit(1); + } + + /* Present a greeting */ + + printf("NuttX FTP Client:\n"); + FFLUSH(); + + /* Setting optind to -1 is a non-standard, backdoor way to reinitialize + * getopt(). getopt() is not thread safe and we have no idea what state + * it is in now! + */ + + optind = -1; + + /* Then enter the command line parsing loop */ + + for (;;) + { + /* Display the prompt string */ + + fputs("nfc> ", stdout); + FFLUSH(); + + /* Get the next line of input */ + + if (fgets(g_line, CONFIG_FTPC_LINELEN, stdin)) + { + /* Parse process the command */ + + (void)ftpc_parse(handle, g_line); + FFLUSH(); + } + } + + return 0; +} diff --git a/apps/examples/hello/Makefile b/apps/examples/hello/Makefile new file mode 100644 index 000000000..0798c5f90 --- /dev/null +++ b/apps/examples/hello/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/examples/hello/Makefile +# +# Copyright (C) 2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Hello, World! Example + +ASRCS = +CSRCS = main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/hello/main.c b/apps/examples/hello/main.c new file mode 100644 index 000000000..308603f33 --- /dev/null +++ b/apps/examples/hello/main.c @@ -0,0 +1,64 @@ +/**************************************************************************** + * examples/hello/main.c + * + * Copyright (C) 2008, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdio.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + printf("Hello, World!!\n"); + return 0; +} + diff --git a/apps/examples/helloxx/Makefile b/apps/examples/helloxx/Makefile new file mode 100644 index 000000000..c34378d24 --- /dev/null +++ b/apps/examples/helloxx/Makefile @@ -0,0 +1,122 @@ +############################################################################ +# apps/examples/helloxx/Makefile +# +# Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Hello, World! C++ Example + +ASRCS = +CSRCS = +CXXSRCS = main.cxx + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) +CXXOBJS = $(CXXSRCS:.cxx=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) $(CXXSRCS) +OBJS = $(AOBJS) $(COBJS) $(CXXOBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# helloxx built-in application info + +APPNAME = helloxx +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend disclean chkcxx + +chkcxx: +ifneq ($(CONFIG_HAVE_CXX),y) + @echo "" + @echo "In order to use this example, you toolchain must support must" + @echo "" + @echo " (1) Explicitly select CONFIG_HAVE_CXX to build in C++ support" + @echo " (2) Define CXX, CXXFLAGS, and COMPILEXX in the Make.defs file" + @echo " of the configuration that you are using." + @echo "" + @exit 1 +endif + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +$(CXXOBJS): %$(OBJEXT): %.cxx + $(call COMPILEXX, $<, $@) + +.built: chkcxx $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_HELLOXX_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/helloxx/main.cxx b/apps/examples/helloxx/main.cxx new file mode 100644 index 000000000..ed48f4961 --- /dev/null +++ b/apps/examples/helloxx/main.cxx @@ -0,0 +1,129 @@ +//*************************************************************************** +// examples/helloxx/main.c +// +// Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt <spudmonkey@racsa.co.cr> +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +//*************************************************************************** + +//*************************************************************************** +// Included Files +//*************************************************************************** + +#include <nuttx/config.h> +#include <nuttx/init.h> +#include <cstdio> +#include <debug.h> + +//*************************************************************************** +// Definitions +//*************************************************************************** + +//*************************************************************************** +// Private Classes +//*************************************************************************** + +class CHelloWorld +{ + public: + CHelloWorld(void) : mSecret(42) { lldbg("Constructor\n"); }; + ~CHelloWorld(void) { lldbg("Destructor\n"); }; + + bool HelloWorld(void) + { + if (mSecret != 42) + { + printf("CHelloWorld::HelloWorld: CONSTRUCTION FAILED!\n"); + return false; + } + else + { + printf("CHelloWorld::HelloWorld: Hello, World!!\n"); + return true; + } + }; + + private: + int mSecret; +}; + +//*************************************************************************** +// Private Data +//*************************************************************************** + +#ifndef CONFIG_EXAMPLES_HELLOXX_NOSTATICCONST +static CHelloWorld g_HelloWorld; +#endif + +//*************************************************************************** +// Public Functions +//*************************************************************************** + +//*************************************************************************** +// user_start +//*************************************************************************** + +/**************************************************************************** + * Name: user_start/nxhello_main + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_HELLOXX_BUILTIN +extern "C" int helloxx_main(int argc, char *argv[]); +# define MAIN_NAME helloxx_main +# define MAIN_STRING "helloxx_main: " +#else +# define MAIN_NAME user_start +# define MAIN_STRING "user_start: " +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ +#ifndef CONFIG_EXAMPLES_HELLOXX_NOSTACKCONST + CHelloWorld HelloWorld; +#endif + CHelloWorld *pHelloWorld = new CHelloWorld; + + printf(MAIN_STRING "Saying hello from the dynamically constructed instance\n"); + pHelloWorld->HelloWorld(); + +#ifndef CONFIG_EXAMPLES_HELLOXX_NOSTACKCONST + printf(MAIN_STRING "Saying hello from the instance constructed on the stack\n"); + HelloWorld.HelloWorld(); +#endif + +#ifndef CONFIG_EXAMPLES_HELLOXX_NOSTATICCONST + printf(MAIN_STRING "Saying hello from the statically constructed instance\n"); + g_HelloWorld.HelloWorld(); +#endif + + delete pHelloWorld; + return 0; +} + diff --git a/apps/examples/hidkbd/Makefile b/apps/examples/hidkbd/Makefile new file mode 100644 index 000000000..e32e628c7 --- /dev/null +++ b/apps/examples/hidkbd/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/examples/hidkbd/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# USB Host HID keyboard Example + +ASRCS = +CSRCS = hidkbd_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/hidkbd/hidkbd_main.c b/apps/examples/hidkbd/hidkbd_main.c new file mode 100644 index 000000000..96864b9f9 --- /dev/null +++ b/apps/examples/hidkbd/hidkbd_main.c @@ -0,0 +1,231 @@ +/**************************************************************************** + * examples/hidkbd/null_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <sched.h> +#include <errno.h> + +#include <nuttx/usb/usbhost.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +/* Sanity checking */ + +#ifndef CONFIG_USBHOST +# error "CONFIG_USBHOST is not defined" +#endif + +#ifdef CONFIG_USBHOST_INT_DISABLE +# error "Interrupt endpoints are disabled (CONFIG_USBHOST_INT_DISABLE)" +#endif + +#ifndef CONFIG_NFILE_DESCRIPTORS +# error "CONFIG_NFILE_DESCRIPTORS > 0 needed" +#endif + +/* Provide some default values for other configuration settings */ + +#ifndef CONFIG_EXAMPLES_HIDKBD_DEFPRIO +# define CONFIG_EXAMPLES_HIDKBD_DEFPRIO 50 +#endif + +#ifndef CONFIG_EXAMPLES_HIDKBD_STACKSIZE +# define CONFIG_EXAMPLES_HIDKBD_STACKSIZE 1024 +#endif + +#ifndef CONFIG_EXAMPLES_HIDKBD_DEVNAME +# define CONFIG_EXAMPLES_HIDKBD_DEVNAME "/dev/kbda" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct usbhost_driver_s *g_drvr; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hidkbd_waiter + * + * Description: + * Wait for USB devices to be connected. + * + ****************************************************************************/ + +static int hidkbd_waiter(int argc, char *argv[]) +{ + bool connected = false; + int ret; + + printf("hidkbd_waiter: Running\n"); + for (;;) + { + /* Wait for the device to change state */ + + ret = DRVR_WAIT(g_drvr, connected); + DEBUGASSERT(ret == OK); + + connected = !connected; + printf("hidkbd_waiter: %s\n", connected ? "connected" : "disconnected"); + + /* Did we just become connected? */ + + if (connected) + { + /* Yes.. enumerate the newly connected device */ + + (void)DRVR_ENUMERATE(g_drvr); + } + } + + /* Keep the compiler from complaining */ + + return 0; +} + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + char buffer[256]; + pid_t pid; + ssize_t nbytes; + int fd; + int ret; + + /* First, register all of the USB host HID keyboard class driver */ + + printf("user_start: Register class drivers\n"); + ret = usbhost_kbdinit(); + if (ret != OK) + { + printf("user_start: Failed to register the KBD class\n"); + } + + /* Then get an instance of the USB host interface */ + + printf("user_start: Initialize USB host keyboard driver\n"); + g_drvr = usbhost_initialize(0); + if (g_drvr) + { + /* Start a thread to handle device connection. */ + + printf("user_start: Start hidkbd_waiter\n"); + +#ifndef CONFIG_CUSTOM_STACK + pid = task_create("usbhost", CONFIG_EXAMPLES_HIDKBD_DEFPRIO, + CONFIG_EXAMPLES_HIDKBD_STACKSIZE, + (main_t)hidkbd_waiter, (const char **)NULL); +#else + pid = task_create("usbhost", CONFIG_EXAMPLES_HIDKBD_DEFPRIO, + (main_t)hidkbd_waiter, (const char **)NULL); +#endif + + /* Now just sleep. Eventually logic here will open the kbd device and + * perform the HID keyboard test. + */ + + for (;;) + { + /* Open the keyboard device. Loop until the device is successfully + * opened. + */ + + do + { + printf("Opening device %s\n", CONFIG_EXAMPLES_HIDKBD_DEVNAME); + fd = open(CONFIG_EXAMPLES_HIDKBD_DEVNAME, O_RDONLY); + if (fd < 0) + { + printf("Failed: %d\n", errno); + fflush(stdout); + sleep(3); + } + } + while (fd < 0); + + printf("Device %s opened\n", CONFIG_EXAMPLES_HIDKBD_DEVNAME); + fflush(stdout); + + /* Loop until there is a read failure */ + + do + { + /* Read a buffer of data */ + + nbytes = read(fd, buffer, 256); + if (nbytes > 0) + { + /* On success, echo the buffer to stdout */ + + (void)write(1, buffer, nbytes); + } + } + while (nbytes >= 0); + + printf("Closing device %s: %d\n", CONFIG_EXAMPLES_HIDKBD_DEVNAME, (int)nbytes); + fflush(stdout); + close(fd); + } + } + return 0; +} diff --git a/apps/examples/igmp/Makefile b/apps/examples/igmp/Makefile new file mode 100755 index 000000000..1e8e96223 --- /dev/null +++ b/apps/examples/igmp/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/examples/igmp/Makefile +# +# Copyright (C) 2010 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# IGMP Networking Example + +ASRCS = +CSRCS = igmp.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/igmp/igmp.c b/apps/examples/igmp/igmp.c new file mode 100755 index 000000000..7f2a8099c --- /dev/null +++ b/apps/examples/igmp/igmp.c @@ -0,0 +1,142 @@ +/**************************************************************************** + * examples/igmp/igmp.c + * + * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> +#include <debug.h> + +#include <net/if.h> +#include <net/uip/uip.h> +#include <apps/netutils/uiplib.h> +#include <apps/netutils/ipmsfilter.h> + +#include "igmp.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Check if the destination address is a multicast address + * + * - IPv4: multicast addresses lie in the class D group -- The address range + * 224.0.0.0 to 239.255.255.255 (224.0.0.0/4) + * + * - IPv6 multicast addresses are have the high-order octet of the + * addresses=0xff (ff00::/8.) + */ + +#if ((CONFIG_EXAMPLE_IGMP_GRPADDR & 0xffff0000) < 0xe0000000ul) || \ + ((CONFIG_EXAMPLE_IGMP_GRPADDR & 0xffff0000) > 0xeffffffful) +# error "Bad range for IGMP group address" +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + struct in_addr addr; +#if defined(CONFIG_EXAMPLE_IGMP_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif + + message("Configuring Ethernet...\n"); + + /* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_IGMP_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_IGMP_IPADDR); + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_IGMP_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_IGMP_NETMASK); + uip_setnetmask("eth0", &addr); + + /* Not much of a test for now */ + /* Join the group */ + + message("Join group...\n"); + addr.s_addr = HTONL(CONFIG_EXAMPLE_IGMP_GRPADDR); + ipmsfilter("eth0", &addr, MCAST_INCLUDE); + + /* Wait a while */ + + message("Wait for timeout...\n"); + sleep(5); + + /* Leave the group */ + + message("Leave group...\n"); + ipmsfilter("eth0", &addr, MCAST_EXCLUDE); + + /* Wait a while */ + + sleep(5); + message("Exiting...\n"); + return 0; +} diff --git a/apps/examples/igmp/igmp.h b/apps/examples/igmp/igmp.h new file mode 100755 index 000000000..e241467c6 --- /dev/null +++ b/apps/examples/igmp/igmp.h @@ -0,0 +1,61 @@ +/**************************************************************************** + * examples/igmp/igmp.h + * + * Copyright (C) 2010 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_IGMP_H +#define __EXAMPLES_IGMP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <debug.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Used lib_rawprintf() so that there is no confusion from buffered IO */ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# define message(...) lib_rawprintf(__VA_ARGS__) +#else +# define message lib_rawprintf +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __EXAMPLES_IGMP_H */ diff --git a/apps/examples/lcdrw/Makefile b/apps/examples/lcdrw/Makefile new file mode 100644 index 000000000..053c62670 --- /dev/null +++ b/apps/examples/lcdrw/Makefile @@ -0,0 +1,105 @@ +############################################################################ +# apps/examples/lcdrw/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# LCD Read/Write Test + +ASRCS = +CSRCS = lcdrw_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# LCD R/W built-in application info + +APPNAME = lcdrw +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_LCDRW_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/lcdrw/lcdrw_main.c b/apps/examples/lcdrw/lcdrw_main.c new file mode 100644 index 000000000..4b717666f --- /dev/null +++ b/apps/examples/lcdrw/lcdrw_main.c @@ -0,0 +1,262 @@ +/**************************************************************************** + * examples/lcdrw/lcdrw_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <nuttx/lcd/lcd.h> +#include <nuttx/nx/nxglib.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* Most of the NX configuration settings are probbably *not* needed by this + * example. But, presumeably you are using NX too and so the checks might + * be good for you. + */ + +#ifndef CONFIG_NX +# error "CONFIG_NX must be defined to use this test" +#endif + +#ifndef CONFIG_NX_LCDDRIVER +# error "CONFIG_NX_LCDDRIVER must be defined to use this test" +#endif + +#ifndef CONFIG_EXAMPLES_LCDRW_BPP +# define CONFIG_EXAMPLES_LCDRW_BPP 16 +#endif + +#if CONFIG_EXAMPLES_LCDRW_BPP != 16 +# error "Currently only RGB565 is supported -- feel free to extend" +#endif + +#ifdef CONFIG_NX_DISABLE_16BPP +# error "CONFIG_NX_DISABLE_16BPP disables 16-bit support" +#endif + +#ifndef CONFIG_EXAMPLES_LDCRW_DEVNO +# define CONFIG_EXAMPLES_LDCRW_DEVNO 0 +#endif + +#ifndef CONFIG_EXAMPLES_LDCRW_XRES +# define CONFIG_EXAMPLES_LDCRW_XRES 240 +#endif + +#ifndef CONFIG_EXAMPLES_LDCRW_YRES +# define CONFIG_EXAMPLES_LDCRW_YRES 320 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct lcdrw_instance_s +{ + /* LCD device handle and planeinfo */ + + FAR struct lcd_dev_s *dev; + struct lcd_planeinfo_s pinfo; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/**************************************************************************** + * Name: lcdrw_initialize + ****************************************************************************/ + +static inline int lcdrw_initialize(FAR struct lcdrw_instance_s *inst) +{ + int ret; + + /* Initialize the LCD device */ + + printf("screens_initialize: Initializing LCD\n"); + ret = up_lcdinitialize(); + if (ret < 0) + { + fprintf(stderr, "screens_initialize: up_lcdinitialize failed: %d\n", -ret); + return ret; + } + + /* Get the device instance. */ + + printf("Get LCD instance\n"); + inst->dev = up_lcdgetdev(CONFIG_EXAMPLES_LDCRW_DEVNO); + if (!inst->dev) + { + fprintf(stderr, "up_lcdgetdev failed, devno=%d\n", CONFIG_EXAMPLES_LDCRW_DEVNO); + return ret; + } + + /* Turn the LCD on at 75% power. This should not be necessary. */ + + (void)inst->dev->setpower(inst->dev, ((3*CONFIG_LCD_MAXPOWER + 3)/4)); + + /* Get the planeinfo structure */ + + ret = inst->dev->getplaneinfo(inst->dev, 0, &inst->pinfo); + if (ret < 0) + { + fprintf(stderr, "getplaneinfo failed: %d\n", ret); + } + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lcdrw_main/user_start + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_LCDRW_BUILTIN +# define MAIN_NAME lcdrw_main +#else +# define MAIN_NAME user_start +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + struct lcdrw_instance_s inst; + nxgl_coord_t row; + nxgl_coord_t col; + uint16_t value; + uint32_t offset; + FAR uint16_t *ptr; + int ret; + + /* Initialize the LCD driver */ + + ret = lcdrw_initialize(&inst); + if (ret < 0) + { + exit(1); + } + + /* Then read each line from the LCD and write to the TIFF file */ + + value = 0; + for (row = 0; row < CONFIG_EXAMPLES_LDCRW_YRES; row++) + { + /* Create a dummy row. The important thing is to try all + * bit combinations in a predictable way. + */ + + ptr = (FAR uint16_t*)inst.pinfo.buffer; + for (col = 0; col < CONFIG_EXAMPLES_LDCRW_XRES; col++) + { + *ptr++ = value++; + } + + /* Write the row to the LCD */ + + ret = inst.pinfo.putrun(row, 0, inst.pinfo.buffer, + CONFIG_EXAMPLES_LDCRW_XRES); + if (ret < 0) + { + fprintf(stderr, "putrun failed: %d\n", ret); + exit(1); + } + } + + /* Print a header */ + + printf(" "); + for (col = 0; col < 15; col++) + { + printf("---%x ", col); + } + printf("---f\n"); + + /* Then read each line back from the LCD (this would hook into + * the TIFF file creation library *very* easily to create a + * TIFF file of the returned values). + */ + + offset = 0; + for (row = 0; row < CONFIG_EXAMPLES_LDCRW_YRES; row++) + { + /* Read the row */ + + ret = inst.pinfo.getrun(row, 0, inst.pinfo.buffer, + CONFIG_EXAMPLES_LDCRW_XRES); + if (ret < 0) + { + fprintf(stderr, "getrun failed: %d\n", ret); + exit(1); + } + + /* Then dump the row to the display */ + + ptr = (FAR uint16_t*)inst.pinfo.buffer; + for (col = 0; col < CONFIG_EXAMPLES_LDCRW_XRES; col++) + { + if ((offset & 15) == 0) + { + printf("%06x ", offset); + } + + value = *ptr++; + offset++; + + if ((offset & 15) == 0) + { + printf("%04x\n", value); + } + else + { + printf("%04x ", value); + } + } + } + fflush(stdout); + + return 0; +} + diff --git a/apps/examples/mm/Makefile b/apps/examples/mm/Makefile new file mode 100644 index 000000000..e5d9ffb4c --- /dev/null +++ b/apps/examples/mm/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/examples/mm/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Memory Management Test + +ASRCS = +CSRCS = mm_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/mm/mm_main.c b/apps/examples/mm/mm_main.c new file mode 100644 index 000000000..036c39047 --- /dev/null +++ b/apps/examples/mm/mm_main.c @@ -0,0 +1,300 @@ +/**************************************************************************** + * examples/mm/mm_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NTEST_ALLOCS 32 + +/* #define STOP_ON_ERRORS do{}while(0) */ +#define STOP_ON_ERRORS exit(1) + +/* All other definitions derive from these two */ + +#define MM_MIN_SHIFT 4 /* 16 bytes */ +#define MM_MIN_CHUNK (1 << MM_MIN_SHIFT) +#define MM_GRAN_MASK (MM_MIN_CHUNK-1) +#define MM_ALIGN_UP(a) (((a) + MM_GRAN_MASK) & ~MM_GRAN_MASK) +#define MM_ALIGN_DOWN(a) ((a) & ~MM_GRAN_MASK) + +#ifdef CONFIG_SMALL_MEMORY +# define SIZEOF_MM_ALLOCNODE 4 +#else +# define SIZEOF_MM_ALLOCNODE 8 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ +/* Test allocations */ + +static const int alloc_sizes[NTEST_ALLOCS] = +{ + 1024, 12, 962, 5692, 10254, 111, 9932, 601, + 222, 2746, 3, 124321, 68, 776, 6750, 852, + 4732, 28, 901, 480, 5011, 1536, 2011, 81647, + 646, 1646, 69179, 194, 2590, 7, 969, 70 +}; + +static const int realloc_sizes[NTEST_ALLOCS] = +{ + 18, 3088, 963, 123, 511, 11666, 3723, 42, + 9374, 1990, 1412, 6, 592, 4088, 11, 5040, + 8663, 91255, 28, 4346, 9172, 168, 229, 4734, + 59139, 221, 7830, 30421, 1666, 4, 812, 416 +}; + +static const int random1[NTEST_ALLOCS] = +{ + 20, 11, 3, 31, 9, 29, 7, 17, + 21, 2, 26, 18, 14, 25, 0, 10, + 27, 19, 22, 28, 8, 30, 12, 15, + 4, 1, 24, 6, 16, 13, 5, 23 +}; + +static const int random2[NTEST_ALLOCS] = +{ + 2, 19, 12, 23, 30, 11, 27, 4, + 20, 7, 0, 16, 28, 15, 5, 24, + 10, 17, 25, 31, 8, 29, 3, 26, + 9, 18, 22, 13, 1, 21, 14, 6 +}; + +static const int random3[NTEST_ALLOCS] = +{ + 8, 17, 3, 18, 26, 23, 30, 11, + 12, 22, 4, 20, 25, 10, 27, 1, + 29, 14, 19, 21, 0, 31, 7, 24, + 9, 15, 2, 28, 16, 6, 13, 5 +}; + +static const int alignment[NTEST_ALLOCS/2] = +{ + 128, 2048, 131072, 8192, 32, 32768, 16384 , 262144, + 512, 4096, 65536, 8, 64, 1024, 16, 4 +}; + +static void *allocs[NTEST_ALLOCS]; +static struct mallinfo alloc_info; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void mm_showmallinfo(void) +{ + alloc_info = mallinfo(); + printf(" mallinfo:\n"); + printf(" Total space allocated from system = %ld\n", + alloc_info.arena); + printf(" Number of non-inuse chunks = %ld\n", + alloc_info.ordblks); + printf(" Largest non-inuse chunk = %ld\n", + alloc_info.mxordblk); + printf(" Total allocated space = %ld\n", + alloc_info.uordblks); + printf(" Total non-inuse space = %ld\n", + alloc_info.fordblks); +} + +static void do_mallocs(void **mem, const int *size, const int *seq, int n) +{ + int i; + int j; + + for (i = 0; i < n; i++) + { + j = seq[i]; + if (!mem[j]) + { + printf("(%d)Allocating %d bytes\n", i, size[j]); + mem[j] = malloc(size[j]); + printf("(%d)Memory allocated at %p\n", i, mem[j]); + if (mem[j] == NULL) + { + int allocsize = MM_ALIGN_UP(size[j] + SIZEOF_MM_ALLOCNODE); + fprintf(stderr, "(%d)malloc failed for allocsize=%d\n", i, allocsize); + if (allocsize > alloc_info.mxordblk) + { + fprintf(stderr, " Normal, largest free block is only %ld\n", alloc_info.mxordblk); + } + else + { + fprintf(stderr, " ERROR largest free block is %ld\n", alloc_info.mxordblk); + exit(1); + } + } + else + { + memset(mem[j], 0xAA, size[j]); + } + + mm_showmallinfo(); + } + } +} + +static void do_reallocs(void **mem, const int *oldsize, const int *newsize, const int *seq, int n) +{ + int i; + int j; + + for (i = 0; i < n; i++) + { + j = seq[i]; + printf("(%d)Re-allocating at %p from %d to %d bytes\n", + i, mem[j], oldsize[j], newsize[j]); + mem[j] = realloc(mem[j], newsize[j]); + printf("(%d)Memory re-allocated at %p\n", i, mem[j]); + if (mem[j] == NULL) + { + int allocsize = MM_ALIGN_UP(newsize[j] + SIZEOF_MM_ALLOCNODE); + fprintf(stderr, "(%d)realloc failed for allocsize=%d\n", i, allocsize); + if (allocsize > alloc_info.mxordblk) + { + fprintf(stderr, " Normal, largest free block is only %ld\n", alloc_info.mxordblk); + } + else + { + fprintf(stderr, " ERROR largest free block is %ld\n", alloc_info.mxordblk); + exit(1); + } + } + else + { + memset(mem[j], 0x55, newsize[j]); + } + + mm_showmallinfo(); + } +} + +static void do_memaligns(void **mem, const int *size, const int *align, const int *seq, int n) +{ + int i; + int j; + + for (i = 0; i < n; i++) + { + j = seq[i]; + printf("(%d)Allocating %d bytes aligned to 0x%08x\n", + i, size[j], align[i]); + mem[j] = memalign(align[i], size[j]); + printf("(%d)Memory allocated at %p\n", i, mem[j]); + if (mem[j] == NULL) + { + int allocsize = MM_ALIGN_UP(size[j] + SIZEOF_MM_ALLOCNODE) + 2*align[i]; + fprintf(stderr, "(%d)memalign failed for allocsize=%d\n", i, allocsize); + if (allocsize > alloc_info.mxordblk) + { + fprintf(stderr, " Normal, largest free block is only %ld\n", alloc_info.mxordblk); + } + else + { + fprintf(stderr, " ERROR largest free block is %ld\n", alloc_info.mxordblk); + exit(1); + } + } + else + { + memset(mem[j], 0x33, size[j]); + } + + mm_showmallinfo(); + } +} + +static void do_frees(void **mem, const int *size, const int *seq, int n) +{ + int i; + int j; + + for (i = 0; i < n; i++) + { + j = seq[i]; + printf("(%d)Releasing memory at %p (size=%d bytes)\n", + i, mem[j], size[j]); + free(mem[j]); + mem[j] = NULL; + + mm_showmallinfo(); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + mm_showmallinfo(); + + /* Allocate some memory */ + + do_mallocs(allocs, alloc_sizes, random1, NTEST_ALLOCS); + + /* Re-allocate the memory */ + + do_reallocs(allocs, alloc_sizes, realloc_sizes, random2, NTEST_ALLOCS); + + /* Release the memory */ + + do_frees(allocs, realloc_sizes, random3, NTEST_ALLOCS); + + /* Allocate aligned memory */ + + do_memaligns(allocs, alloc_sizes, alignment, random2, NTEST_ALLOCS/2); + do_memaligns(allocs, alloc_sizes, alignment, &random2[NTEST_ALLOCS/2], NTEST_ALLOCS/2); + + /* Release aligned memory */ + + do_frees(allocs, alloc_sizes, random1, NTEST_ALLOCS); + + printf("TEST COMPLETE\n"); + return 0; +} diff --git a/apps/examples/mount/Makefile b/apps/examples/mount/Makefile new file mode 100644 index 000000000..7e48ea44a --- /dev/null +++ b/apps/examples/mount/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/Makefile +# +# Copyright (C) 2007-2008, 2010-2010 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# mount() test + +ASRCS = +CSRCS = mount_main.c ramdisk.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/mount/mount.h b/apps/examples/mount/mount.h new file mode 100644 index 000000000..68a03674d --- /dev/null +++ b/apps/examples/mount/mount.h @@ -0,0 +1,96 @@ +/**************************************************************************** + * examples/mount/mount.h + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_MOUNT_MOUNT_H +#define __EXAMPLES_MOUNT_MOUNT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Configure the test */ + +#if defined(CONFIG_EXAMPLES_MOUNT_DEVNAME) +# if !defined(CONFIG_FS_WRITABLE) +# error "Writable filesystem required in this configuration" +# endif +# undef CONFIG_EXAMPLES_MOUNT_NSECTORS +# undef CONFIG_EXAMPLES_MOUNT_SECTORSIZE +# undef CONFIG_EXAMPLES_MOUNT_RAMDEVNO +# define MOUNT_DEVNAME CONFIG_EXAMPLES_MOUNT_DEVNAME +#else +# if !defined(CONFIG_FS_FAT) +# error "CONFIG_FS_FAT required in this configuration" +# endif +# if !defined(CONFIG_EXAMPLES_MOUNT_SECTORSIZE) +# define CONFIG_EXAMPLES_MOUNT_SECTORSIZE 512 +# endif +# if !defined(CONFIG_EXAMPLES_MOUNT_NSECTORS) +# define CONFIG_EXAMPLES_MOUNT_NSECTORS 2048 +# endif +# if !defined(CONFIG_EXAMPLES_MOUNT_RAMDEVNO) +# define CONFIG_EXAMPLES_MOUNT_RAMDEVNO 0 +# endif +# define STR_RAMDEVNO(m) #m +# define MKMOUNT_DEVNAME(m) "/dev/ram" STR_RAMDEVNO(m) +# define MOUNT_DEVNAME MKMOUNT_DEVNAME(CONFIG_EXAMPLES_MOUNT_RAMDEVNO) +#endif + + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +extern const char g_source[]; /* Mount 'source' path */ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_MOUNT_DEVNAME +extern int create_ramdisk(void); +#endif + +#endif /* __EXAMPLES_MOUNT_MOUNT_H */ diff --git a/apps/examples/mount/mount_main.c b/apps/examples/mount/mount_main.c new file mode 100644 index 000000000..00070b94c --- /dev/null +++ b/apps/examples/mount/mount_main.c @@ -0,0 +1,754 @@ +/**************************************************************************** + * examples/mount/mount_main.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/mount.h> +#include <sys/stat.h> +#include <sys/statfs.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> + +#include "mount.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define TEST_USE_STAT 1 +#define TEST_SHOW_DIRECTORIES 1 +#define TEST_USE_STATFS 1 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_mntdir[] = "/mnt"; +static const char g_target[] = "/mnt/fs"; +static const char g_filesystemtype[] = "vfat"; + +static const char g_testdir1[] = "/mnt/fs/TestDir"; +static const char g_testdir2[] = "/mnt/fs/NewDir1"; +static const char g_testdir3[] = "/mnt/fs/NewDir2"; +static const char g_testdir4[] = "/mnt/fs/NewDir3"; +#ifdef CONFIG_EXAMPLES_MOUNT_DEVNAME +static const char g_testfile1[] = "/mnt/fs/TestDir/TestFile.txt"; +#endif +static const char g_testfile2[] = "/mnt/fs/TestDir/WrTest1.txt"; +static const char g_testfile3[] = "/mnt/fs/NewDir1/WrTest2.txt"; +static const char g_testfile4[] = "/mnt/fs/NewDir3/Renamed.txt"; +static const char g_testmsg[] = "This is a write test"; + +static int g_nerrors = 0; + +static char g_namebuffer[256]; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + + const char g_source[] = MOUNT_DEVNAME; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef TEST_USE_STAT +static void show_stat(const char *path, struct stat *ps) +{ + printf("%s stat:\n", path); + printf("\tmode : %08x\n", ps->st_mode); + if (S_ISREG(ps->st_mode)) + { + printf("\ttype : File\n"); + } + else if (S_ISDIR(ps->st_mode)) + { + printf("\ttype : Directory\n"); + } + else if (S_ISCHR(ps->st_mode)) + { + printf("\ttype : Character driver\n"); + } + else if (S_ISBLK(ps->st_mode)) + { + printf("\ttype : Block driver\n"); + } + else + { + printf("\ttype : Unknown\n"); + } + + printf("\tsize : %d (bytes)\n", ps->st_size); + printf("\tblock size : %d (bytes)\n", ps->st_blksize); + printf("\tsize : %d (blocks)\n", ps->st_blocks); + printf("\taccess time : %d\n", ps->st_atime); + printf("\tmodify time : %d\n", ps->st_mtime); + printf("\tchange time : %d\n", ps->st_ctime); +} +#endif + +/**************************************************************************** + * Name: show_statfs + ****************************************************************************/ + +#ifdef TEST_USE_STATFS +static void show_statfs(const char *path) +{ + struct statfs buf; + int ret; + + /* Try stat() against a file or directory. It should fail with expectederror */ + + printf("show_statfs: Try statfs(%s)\n", path); + ret = statfs(path, &buf); + if (ret == 0) + { + printf("show_statfs: statfs(%s) succeeded\n", path); + printf("\tFS Type : %0x\n", buf.f_type); + printf("\tBlock size : %d\n", buf.f_bsize); + printf("\tNumber of blocks : %d\n", buf.f_blocks); + printf("\tFree blocks : %d\n", buf.f_bfree); + printf("\tFree user blocks : %d\n", buf.f_bavail); + printf("\tNumber file nodes : %d\n", buf.f_files); + printf("\tFree file nodes : %d\n", buf.f_ffree); + printf("\tFile name length : %d\n", buf.f_namelen); + } + else + { + printf("show_statfs: ERROR statfs(%s) failed with errno=%d\n", + path, errno); + g_nerrors++; + } +} +#else +# define show_statfs(p) +#endif + +/**************************************************************************** + * Name: show_directories + ****************************************************************************/ + +#ifdef TEST_SHOW_DIRECTORIES +static void show_directories(const char *path, int indent) +{ + DIR *dirp; + struct dirent *direntry; + int i; + + dirp = opendir(path); + if ( !dirp ) + { + printf("show_directories: ERROR opendir(\"%s\") failed with errno=%d\n", + path, errno); + g_nerrors++; + return; + } + + for (direntry = readdir(dirp); direntry; direntry = readdir(dirp)) + { + for (i = 0; i < 2*indent; i++) + { + putchar(' '); + } + if (DIRENT_ISDIRECTORY(direntry->d_type)) + { + char *subdir; + printf("%s/\n", direntry->d_name); + sprintf(g_namebuffer, "%s/%s", path, direntry->d_name); + subdir = strdup(g_namebuffer); + show_directories( subdir, indent + 1); + free(subdir); + } + else + { + printf("%s\n", direntry->d_name); + } + } + + closedir(dirp); +} +#else +# define show_directories(p,i) +#endif + +/**************************************************************************** + * Name: fail_read_open + ****************************************************************************/ +#ifdef CONFIG_EXAMPLES_MOUNT_DEVNAME +static void fail_read_open(const char *path, int expectederror) +{ + int fd; + + printf("fail_read_open: Try open(%s) for reading\n", path); + + fd = open(path, O_RDONLY); + if (fd >= 0) + { + printf("fail_read_open: ERROR open(%s) succeeded\n", path); + g_nerrors++; + close(fd); + } + else if (errno != expectederror) + { + printf("fail_read_open: ERROR open(%s) failed with errno=%d (expected %d)\n", + path, errno, expectederror); + g_nerrors++; + } +} +#endif + +/**************************************************************************** + * Name: read_test_file + ****************************************************************************/ + +static void read_test_file(const char *path) +{ + char buffer[128]; + int nbytes; + int fd; + + /* Read a test file that is already on the test file system image */ + + printf("read_test_file: opening %s for reading\n", path); + + fd = open(path, O_RDONLY); + if (fd < 0) + { + printf("read_test_file: ERROR failed to open %s, errno=%d\n", + path, errno); + g_nerrors++; + } + else + { + memset(buffer, 0, 128); + nbytes = read(fd, buffer, 128); + if (nbytes < 0) + { + printf("read_test_file: ERROR failed to read from %s, errno=%d\n", + path, errno); + g_nerrors++; + } + else + { + buffer[127]='\0'; + printf("read_test_file: Read \"%s\" from %s\n", buffer, path); + } + close(fd); + } +} + +/**************************************************************************** + * Name: write_test_file + ****************************************************************************/ + +static void write_test_file(const char *path) +{ + int fd; + + /* Write a test file into a pre-existing file on the test file system */ + + printf("write_test_file: opening %s for writing\n", path); + + fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd < 0) + { + printf("write_test_file: ERROR failed to open %s for writing, errno=%d\n", + path, errno); + g_nerrors++; + } + else + { + int nbytes = write(fd, g_testmsg, strlen(g_testmsg)); + if (nbytes < 0) + { + printf("write_test_file: ERROR failed to write to %s, errno=%d\n", + path, errno); + g_nerrors++; + } + else + { + printf("write_test_file: wrote %d bytes to %s\n", nbytes, path); + } + close(fd); + } +} + +/**************************************************************************** + * Name: fail_mkdir + ****************************************************************************/ + +static void fail_mkdir(const char *path, int expectederror) +{ + int ret; + + /* Try mkdir() against a file or directory. It should fail with expectederror */ + + printf("fail_mkdir: Try mkdir(%s)\n", path); + + ret = mkdir(path, 0666); + if (ret == 0) + { + printf("fail_mkdir: ERROR mkdir(%s) succeeded\n", path); + g_nerrors++; + } + else if (errno != expectederror) + { + printf("fail_mkdir: ERROR mkdir(%s) failed with errno=%d (expected %d)\n", + path, errno, expectederror); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: succeed_mkdir + ****************************************************************************/ + +static void succeed_mkdir(const char *path) +{ + int ret; + + printf("succeed_mkdir: Try mkdir(%s)\n", path); + + ret = mkdir(path, 0666); + if (ret != 0) + { + printf("succeed_mkdir: ERROR mkdir(%s) failed with errno=%d\n", + path, errno); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: fail_rmdir + ****************************************************************************/ + +static void fail_rmdir(const char *path, int expectederror) +{ + int ret; + + /* Try rmdir() against a file or directory. It should fail with expectederror */ + + printf("fail_rmdir: Try rmdir(%s)\n", path); + + ret = rmdir(path); + if (ret == 0) + { + printf("fail_rmdir: ERROR rmdir(%s) succeeded\n", path); + g_nerrors++; + } + else if (errno != expectederror) + { + printf("fail_rmdir: ERROR rmdir(%s) failed with errno=%d (expected %d)\n", + path, errno, expectederror); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: succeed_rmdir + ****************************************************************************/ + +static void succeed_rmdir(const char *path) +{ + int ret; + + printf("succeed_rmdir: Try rmdir(%s)\n", path); + + ret = rmdir(path); + if (ret != 0) + { + printf("succeed_rmdir: ERROR rmdir(%s) failed with errno=%d\n", + path, errno); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: fail_unlink + ****************************************************************************/ + +static void fail_unlink(const char *path, int expectederror) +{ + int ret; + + /* Try unlink() against a file or directory. It should fail with expectederror */ + + printf("fail_unlink: Try unlink(%s)\n", path); + + ret = unlink(path); + if (ret == 0) + { + printf("fail_unlink: ERROR unlink(%s) succeeded\n", path); + g_nerrors++; + } + else if (errno != expectederror) + { + printf("fail_unlink: ERROR unlink(%s) failed with errno=%d (expected %d)\n", + path, errno, expectederror); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: succeed_unlink + ****************************************************************************/ + +static void succeed_unlink(const char *path) +{ + int ret; + + /* Try unlink() against the test file. It should succeed. */ + + printf("succeed_unlink: Try unlink(%s)\n", path); + + ret = unlink(path); + if (ret != 0) + { + printf("succeed_unlink: ERROR unlink(%s) failed with errno=%d\n", + path, errno); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: fail_rename + ****************************************************************************/ + +static void fail_rename(const char *oldpath, const char *newpath, int expectederror) +{ + int ret; + + /* Try rename() against a file or directory. It should fail with expectederror */ + + printf("fail_rename: Try rename(%s->%s)\n", oldpath, newpath); + + ret = rename(oldpath, newpath); + if (ret == 0) + { + printf("fail_rename: ERROR rename(%s->%s) succeeded\n", + oldpath, newpath); + g_nerrors++; + } + else if (errno != expectederror) + { + printf("fail_rename: ERROR rename(%s->%s) failed with errno=%d (expected %d)\n", + oldpath, newpath, errno, expectederror); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: succeed_rename + ****************************************************************************/ + +static void succeed_rename(const char *oldpath, const char *newpath) +{ + int ret; + + printf("succeed_rename: Try rename(%s->%s)\n", oldpath, newpath); + + ret = rename(oldpath, newpath); + if (ret != 0) + { + printf("succeed_rename: ERROR rename(%s->%s) failed with errno=%d\n", + oldpath, newpath, errno); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: fail_stat + ****************************************************************************/ + +#ifdef TEST_USE_STAT +static void fail_stat(const char *path, int expectederror) +{ + struct stat buf; + int ret; + + /* Try stat() against a file or directory. It should fail with expectederror */ + + printf("fail_stat: Try stat(%s)\n", path); + + ret = stat(path, &buf); + if (ret == 0) + { + printf("fail_stat: ERROR stat(%s) succeeded\n", path); + show_stat(path, &buf); + g_nerrors++; + } + else if (errno != expectederror) + { + printf("fail_stat: ERROR stat(%s) failed with errno=%d (expected %d)\n", + path, errno, expectederror); + g_nerrors++; + } +} +#else +# define fail_stat(p,e); +#endif + +/**************************************************************************** + * Name: succeed_stat + ****************************************************************************/ + +#ifdef TEST_USE_STAT +static void succeed_stat(const char *path) +{ + struct stat buf; + int ret; + + printf("succeed_stat: Try stat(%s)\n", path); + + ret = stat(path, &buf); + if (ret != 0) + { + printf("succeed_stat: ERROR stat(%s) failed with errno=%d\n", + path, errno); + g_nerrors++; + } + else + { + printf("succeed_stat: stat(%s) succeeded\n", path); + show_stat(path, &buf); + } +} +#else +#define succeed_stat(p) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + int ret; + +#ifndef CONFIG_EXAMPLES_MOUNT_DEVNAME + /* Create a RAM disk for the test */ + + ret = create_ramdisk(); + if (ret < 0) + { + printf("user_start: ERROR failed to create RAM disk\n"); + return 1; + } +#endif + + /* Mount the test file system (see arch/sim/src/up_deviceimage.c */ + + printf("user_start: mounting %s filesystem at target=%s with source=%s\n", + g_filesystemtype, g_target, g_source); + + ret = mount(g_source, g_target, g_filesystemtype, 0, NULL); + printf("user_start: mount() returned %d\n", ret); + + if (ret == 0) + { + show_statfs(g_mntdir); + show_statfs(g_target); + +#ifdef CONFIG_EXAMPLES_MOUNT_DEVNAME + /* Read a test file that is already on the test file system image */ + + show_directories("", 0); + succeed_stat(g_testfile1); + show_statfs(g_testfile1); + read_test_file(g_testfile1); +#else + /* Create the test directory that would have been on the canned filesystem */ + + succeed_mkdir(g_testdir1); + show_directories("", 0); + succeed_stat(g_testdir1); + show_statfs(g_testdir1); +#endif + + /* Write a test file into a pre-existing directory on the test file system */ + + fail_stat(g_testfile2, ENOENT); + write_test_file(g_testfile2); + show_directories("", 0); + succeed_stat(g_testfile2); + show_statfs(g_testfile2); + + /* Read the file that we just wrote */ + + read_test_file(g_testfile2); + + /* Try rmdir() against a file on the directory. It should fail with ENOTDIR */ +#ifdef CONFIG_EXAMPLES_MOUNT_DEVNAME + fail_rmdir(g_testfile1, ENOTDIR); +#endif + + /* Try rmdir() against the test directory. It should fail with ENOTEMPTY */ + + fail_rmdir(g_testdir1, ENOTEMPTY); + + /* Try unlink() against the test directory. It should fail with EISDIR */ + + fail_unlink(g_testdir1, EISDIR); + + /* Try unlink() against the test file1. It should succeed. */ +#ifdef CONFIG_EXAMPLES_MOUNT_DEVNAME + succeed_unlink(g_testfile1); + fail_stat(g_testfile1, ENOENT); + show_directories("", 0); +#endif + + /* Attempt to open testfile1 should fail with ENOENT */ +#ifdef CONFIG_EXAMPLES_MOUNT_DEVNAME + fail_read_open(g_testfile1, ENOENT); +#endif + /* Try rmdir() against the test directory. It should still fail with ENOTEMPTY */ + + fail_rmdir(g_testdir1, ENOTEMPTY); + + /* Try mkdir() against the test file2. It should fail with EEXIST. */ + + fail_mkdir(g_testfile2, EEXIST); + + /* Try unlink() against the test file2. It should succeed. */ + + succeed_unlink(g_testfile2); + show_directories("", 0); + fail_stat(g_testfile2, ENOENT); + + /* Try mkdir() against the test dir1. It should fail with EEXIST. */ + + fail_mkdir(g_testdir1, EEXIST); + + /* Try rmdir() against the test directory. mkdir should now succeed. */ + + succeed_rmdir(g_testdir1); + show_directories("", 0); + fail_stat(g_testdir1, ENOENT); + + /* Try mkdir() against the test dir2. It should succeed */ + + succeed_mkdir(g_testdir2); + show_directories("", 0); + succeed_stat(g_testdir2); + show_statfs(g_testdir2); + + /* Try mkdir() against the test dir2. It should fail with EXIST */ + + fail_mkdir(g_testdir2, EEXIST); + + /* Write a test file into a new directory on the test file system */ + + fail_stat(g_testfile3, ENOENT); + write_test_file(g_testfile3); + show_directories("", 0); + succeed_stat(g_testfile3); + show_statfs(g_testfile3); + + /* Read the file that we just wrote */ + + read_test_file(g_testfile3); + + /* Use mkdir() to create test dir3. It should succeed */ + + fail_stat(g_testdir3, ENOENT); + succeed_mkdir(g_testdir3); + show_directories("", 0); + succeed_stat(g_testdir3); + show_statfs(g_testdir3); + + /* Try rename() on the root directory. Should fail with EXDEV*/ + + fail_rename(g_target, g_testdir4, EXDEV); + + /* Try rename() to an existing directory. Should fail with EEXIST */ + + fail_rename(g_testdir2, g_testdir3, EEXIST); + + /* Try rename() to a non-existing directory. Should succeed */ + + fail_stat(g_testdir4, ENOENT); + succeed_rename(g_testdir3, g_testdir4); + show_directories("", 0); + fail_stat(g_testdir3, ENOENT); + succeed_stat(g_testdir4); + show_statfs(g_testdir4); + + /* Try rename() of file. Should work. */ + + fail_stat(g_testfile4, ENOENT); + succeed_rename(g_testfile3, g_testfile4); + show_directories("", 0); + fail_stat(g_testfile3, ENOENT); + succeed_stat(g_testfile4); + show_statfs(g_testfile4); + + /* Make sure that we can still read the renamed file */ + + read_test_file(g_testfile4); + + /* Unmount the file system */ + + printf("user_start: Try unmount(%s)\n", g_target); + + ret = umount(g_target); + if (ret != 0) + { + printf("user_start: ERROR umount() failed, errno %d\n", errno); + g_nerrors++; + } + + printf("user_start: %d errors reported\n", g_nerrors); + } + + fflush(stdout); + return 0; +} diff --git a/apps/examples/mount/ramdisk.c b/apps/examples/mount/ramdisk.c new file mode 100644 index 000000000..f596dae52 --- /dev/null +++ b/apps/examples/mount/ramdisk.c @@ -0,0 +1,141 @@ +/**************************************************************************** + * examples/mount/ramdisk.c + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <nuttx/ramdisk.h> +#include <nuttx/mkfatfs.h> + +#include "mount.h" + +#ifndef CONFIG_EXAMPLES_MOUNT_DEVNAME + +/**************************************************************************** + * Private Definitions + ****************************************************************************/ + +#define BUFFER_SIZE (CONFIG_EXAMPLES_MOUNT_NSECTORS*CONFIG_EXAMPLES_MOUNT_SECTORSIZE) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct fat_format_s g_fmt = FAT_FORMAT_INITIALIZER; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: create_ramdisk + * + * Description: + * Create a RAM disk of the specified size formatting with a FAT file + * system + * + * Input Parameters: + * None + * + * Return: + * Zero on success, a negated errno on failure. + * + ****************************************************************************/ + +int create_ramdisk(void) +{ + char *pbuffer; + int ret; + + /* Allocate a buffer to hold the file system image. */ + + pbuffer = (char*)malloc(BUFFER_SIZE); + if (!pbuffer) + { + printf("create_ramdisk: Failed to allocate ramdisk of size %d\n", + BUFFER_SIZE); + return -ENOMEM; + } + + /* Register a RAMDISK device to manage this RAM image */ + + ret = ramdisk_register(CONFIG_EXAMPLES_MOUNT_RAMDEVNO, + pbuffer, + CONFIG_EXAMPLES_MOUNT_NSECTORS, + CONFIG_EXAMPLES_MOUNT_SECTORSIZE, + true); + if (ret < 0) + { + printf("create_ramdisk: Failed to register ramdisk at %s: %d\n", + g_source, -ret); + free(pbuffer); + return ret; + } + + /* Create a FAT filesystem on the ramdisk */ + + ret = mkfatfs(g_source, &g_fmt); + if (ret < 0) + { + printf("create_ramdisk: Failed to create FAT filesystem on ramdisk at %s\n", + g_source); + /* free(pbuffer); -- RAM disk is registered */ + return ret; + } + + return 0; +} +#endif /* !CONFIG_EXAMPLES_MOUNT_DEVNAME */ diff --git a/apps/examples/nettest/Makefile b/apps/examples/nettest/Makefile new file mode 100644 index 000000000..ac07665ab --- /dev/null +++ b/apps/examples/nettest/Makefile @@ -0,0 +1,142 @@ +############################################################################ +# examples/nettest/Makefile +# +# Copyright (C) 2007-2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Basic TCP networking test + +TARG_ASRCS = +TARG_AOBJS = $(TARG_ASRCS:.S=$(OBJEXT)) + +TARG_CSRCS = nettest.c +ifeq ($(CONFIG_EXAMPLE_NETTEST_SERVER),y) +TARG_CSRCS += nettest_server.c +else +TARG_CSRCS += nettest_client.c +endif + +TARG_COBJS = $(TARG_CSRCS:.c=$(OBJEXT)) + +TARG_SRCS = $(TARG_ASRCS) $(TARG_CSRCS) +TARG_OBJS = $(TARG_AOBJS) $(TARG_COBJS) + +TARG_POSIX = "$(APPDIR)/libapps$(LIBEXT)" +ifeq ($(WINTOOL),y) + TARG_BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + TARG_BIN = "$(TARG_POSIX)" +endif + +HOSTCFLAGS += -DCONFIG_EXAMPLE_NETTEST_HOST=1 +ifeq ($(CONFIG_EXAMPLE_NETTEST_SERVER),y) +HOSTCFLAGS += -DCONFIG_EXAMPLE_NETTEST_SERVER=1 \ + -DCONFIG_EXAMPLE_NETTEST_CLIENTIP="$(CONFIG_EXAMPLE_NETTEST_CLIENTIP)" +endif +ifeq ($(CONFIG_EXAMPLE_NETTEST_PERFORMANCE),y) +HOSTCFLAGS += -DCONFIG_EXAMPLE_NETTEST_PERFORMANCE=1 +endif + + + +HOST_SRCS = host.c +ifeq ($(CONFIG_EXAMPLE_NETTEST_SERVER),y) +HOST_SRCS += nettest_client.c +else +HOST_SRCS += nettest_server.c +endif + +HOST_OBJS = $(HOST_SRCS:.c=.o) +HOST_BIN = host + +ROOTDEPPATH = --dep-path . + +# NET test built-in application info + +APPNAME = nettest +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built $(HOST_BIN) +.PHONY: clean depend disclean + +$(TARG_AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(TARG_COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +$(HOST_OBJS): %.o: %.c + @echo "CC: $<" + @$(HOSTCC) -c $(HOSTCFLAGS) $< -o $@ + +$(HOST_BIN): $(HOST_OBJS) + @echo "LD: $@" + @$(HOSTCC) $(HOSTLDFLAGS) $(HOST_OBJS) -o $@ + +.built: $(TARG_OBJS) + @( for obj in $(TARG_OBJS) ; do \ + $(call ARCHIVE, $(TARG_BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(TARG_SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(TARG_SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f $(TARG_POSIX) $(HOST_BIN) .built *.o *~ .*.swp + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/nettest/host.c b/apps/examples/nettest/host.c new file mode 100644 index 000000000..25cb85455 --- /dev/null +++ b/apps/examples/nettest/host.c @@ -0,0 +1,63 @@ +/**************************************************************************** + * examples/nettest/host.c + * + * Copyright (C) 2007, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "nettest.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * main + ****************************************************************************/ + +int main(int argc, char **argv, char **envp) +{ +#ifdef CONFIG_EXAMPLE_NETTEST_SERVER + send_client(); +#else + recv_server(); +#endif + + return 0; +} diff --git a/apps/examples/nettest/nettest.c b/apps/examples/nettest/nettest.c new file mode 100644 index 000000000..7160e693a --- /dev/null +++ b/apps/examples/nettest/nettest.c @@ -0,0 +1,121 @@ +/**************************************************************************** + * examples/nettest/nettest.c + * + * Copyright (C) 2007, 2009-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdio.h> +#include <debug.h> + +#include <net/if.h> +#include <net/uip/uip.h> +#include <apps/netutils/uiplib.h> + +#include "nettest.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* If CONFIG_NSH_BUILTIN_APPS is defined, then it is assumed that you want + * to execute the DHCPD daemon as an NSH built-in task. + */ + +#ifdef CONFIG_NSH_BUILTIN_APPS +# define MAIN_NAME nettest_main +# define MAIN_NAME_STRING "nettest_main" +#else +# define MAIN_NAME user_start +# define MAIN_NAME_STRING "user_start" +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int MAIN_NAME(int argc, char *argv[]) +{ + struct in_addr addr; +#ifdef CONFIG_EXAMPLE_NETTEST_NOMAC + uint8_t mac[IFHWADDRLEN]; +#endif + +/* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_NETTEST_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_NETTEST_IPADDR); + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_NETTEST_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_NETTEST_NETMASK); + uip_setnetmask("eth0", &addr); + +#ifdef CONFIG_EXAMPLE_NETTEST_SERVER + recv_server(); +#else + send_client(); +#endif + + return 0; +} diff --git a/apps/examples/nettest/nettest.h b/apps/examples/nettest/nettest.h new file mode 100644 index 000000000..b5b619175 --- /dev/null +++ b/apps/examples/nettest/nettest.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * examples/nettest/nettest.h + * + * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_NETTEST_H +#define __EXAMPLES_NETTEST_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLE_NETTEST_HOST +#else +# include <debug.h> +#endif + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLE_NETTEST_HOST + /* HTONS/L macros are unique to uIP */ + +# define HTONS(a) htons(a) +# define HTONL(a) htonl(a) + + /* Used printf for debug output */ + +# ifdef CONFIG_CPP_HAVE_VARARGS +# define message(...) printf(__VA_ARGS__) +# else +# define message printf +# endif + + /* Have SO_LINGER */ + +# define NETTEST_HAVE_SOLINGER 1 + +#else + + /* Used lib_rawprintf() so that there is not confusion from buffered IO */ + +# ifdef CONFIG_CPP_HAVE_VARARGS +# define message(...) lib_rawprintf(__VA_ARGS__) +# else +# define message lib_rawprintf +# endif + + /* At present, uIP does only abortive disconnects */ + +# undef NETTEST_HAVE_SOLINGER +#endif + +#define PORTNO 5471 +#define SENDSIZE 4096 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +extern void send_client(void); +extern void recv_server(void); + +#endif /* __EXAMPLES_NETTEST_H */ diff --git a/apps/examples/nettest/nettest_client.c b/apps/examples/nettest/nettest_client.c new file mode 100644 index 000000000..5f95d7b70 --- /dev/null +++ b/apps/examples/nettest/nettest_client.c @@ -0,0 +1,205 @@ +/**************************************************************************** + * examples/nettest/nettest-client.c + * + * Copyright (C) 2007, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/socket.h> +#include <netinet/in.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "nettest.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void send_client(void) +{ + struct sockaddr_in myaddr; + char *outbuf; +#ifndef CONFIG_EXAMPLE_NETTEST_PERFORMANCE + char *inbuf; +#endif + int sockfd; + int nbytessent; +#ifndef CONFIG_EXAMPLE_NETTEST_PERFORMANCE + int nbytesrecvd; + int totalbytesrecvd; +#endif + int ch; + int i; + + /* Allocate buffers */ + + outbuf = (char*)malloc(SENDSIZE); +#ifndef CONFIG_EXAMPLE_NETTEST_PERFORMANCE + inbuf = (char*)malloc(SENDSIZE); + if (!outbuf || !inbuf) +#else + if (!outbuf) +#endif + { + message("client: failed to allocate buffers\n"); + exit(1); + } + + /* Create a new TCP socket */ + + sockfd = socket(PF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + { + message("client socket failure %d\n", errno); + goto errout_with_buffers; + } + + /* Connect the socket to the server */ + + myaddr.sin_family = AF_INET; + myaddr.sin_port = HTONS(PORTNO); +#if 0 + myaddr.sin_addr.s_addr = HTONL(INADDR_LOOPBACK); +#else + myaddr.sin_addr.s_addr = HTONL(CONFIG_EXAMPLE_NETTEST_CLIENTIP); +#endif + + message("client: Connecting...\n"); + if (connect( sockfd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0) + { + message("client: connect failure: %d\n", errno); + goto errout_with_socket; + } + message("client: Connected\n"); + + /* Initialize the buffer */ + + ch = 0x20; + for (i = 0; i < SENDSIZE; i++ ) + { + outbuf[i] = ch; + if (++ch > 0x7e) + { + ch = 0x20; + } + } + +#ifdef CONFIG_EXAMPLE_NETTEST_PERFORMANCE + /* Then send messages forever */ + + for (;;) + { + nbytessent = send(sockfd, outbuf, SENDSIZE, 0); + if (nbytessent < 0) + { + message("client: send failed: %d\n", errno); + goto errout_with_socket; + } + else if (nbytessent != SENDSIZE) + { + message("client: Bad send length=%d: %d of \n", + nbytessent, SENDSIZE); + goto errout_with_socket; + } + message("Sent %d bytes\n", nbytessent); + } +#else + /* Then send and receive one message */ + + message("client: Sending %d bytes\n", SENDSIZE); + nbytessent = send(sockfd, outbuf, SENDSIZE, 0); + message("client: Sent %d bytes\n", nbytessent); + + if (nbytessent < 0) + { + message("client: send failed: %d\n", errno); + goto errout_with_socket; + } + else if (nbytessent != SENDSIZE) + { + message("client: Bad send length: %d Expected: %d\n", nbytessent, SENDSIZE); + goto errout_with_socket; + } + + totalbytesrecvd = 0; + do + { + message("client: Receiving...\n"); + nbytesrecvd = recv(sockfd, &inbuf[totalbytesrecvd], SENDSIZE - totalbytesrecvd, 0); + + if (nbytesrecvd < 0) + { + message("client: recv failed: %d\n", errno); + goto errout_with_socket; + } + totalbytesrecvd += nbytesrecvd; + message("client: Received %d of %d bytes\n", totalbytesrecvd, SENDSIZE); + } + while (totalbytesrecvd < SENDSIZE); + + if (totalbytesrecvd != SENDSIZE) + { + message("client: Bad recv length: %d Expected: %d\n", totalbytesrecvd, SENDSIZE); + goto errout_with_socket; + } + else if (memcmp(inbuf, outbuf, SENDSIZE) != 0) + { + message("client: Received buffer does not match sent buffer\n"); + goto errout_with_socket; + } + + close(sockfd); + free(outbuf); +#ifndef CONFIG_EXAMPLE_NETTEST_PERFORMANCE + free(inbuf); +#endif + return; +#endif + +errout_with_socket: + close(sockfd); + +errout_with_buffers: + free(outbuf); +#ifndef CONFIG_EXAMPLE_NETTEST_PERFORMANCE + free(inbuf); +#endif + exit(1); +} diff --git a/apps/examples/nettest/nettest_server.c b/apps/examples/nettest/nettest_server.c new file mode 100644 index 000000000..45ef3a39a --- /dev/null +++ b/apps/examples/nettest/nettest_server.c @@ -0,0 +1,235 @@ +/**************************************************************************** + * examples/nettest/nettest-server.c + * + * Copyright (C) 2007, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +#include "nettest.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void recv_server(void) +{ + struct sockaddr_in myaddr; +#ifdef NETTEST_HAVE_SOLINGER + struct linger ling; +#endif + char *buffer; + int listensd; + int acceptsd; + socklen_t addrlen; + int nbytesread; +#ifndef CONFIG_EXAMPLE_NETTEST_PERFORMANCE + int totalbytesread; + int nbytessent; + int ch; + int i; +#endif + int optval; + + /* Allocate a BIG buffer */ + + buffer = (char*)malloc(2*SENDSIZE); + if (!buffer) + { + message("server: failed to allocate buffer\n"); + exit(1); + } + + + /* Create a new TCP socket */ + + listensd = socket(PF_INET, SOCK_STREAM, 0); + if (listensd < 0) + { + message("server: socket failure: %d\n", errno); + goto errout_with_buffer; + } + + /* Set socket to reuse address */ + + optval = 1; + if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0) + { + message("server: setsockopt SO_REUSEADDR failure: %d\n", errno); + goto errout_with_listensd; + } + + /* Bind the socket to a local address */ + + myaddr.sin_family = AF_INET; + myaddr.sin_port = HTONS(PORTNO); + myaddr.sin_addr.s_addr = INADDR_ANY; + + if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0) + { + message("server: bind failure: %d\n", errno); + goto errout_with_listensd; + } + + /* Listen for connections on the bound TCP socket */ + + if (listen(listensd, 5) < 0) + { + message("server: listen failure %d\n", errno); + goto errout_with_listensd; + } + + /* Accept only one connection */ + + message("server: Accepting connections on port %d\n", PORTNO); + addrlen = sizeof(struct sockaddr_in); + acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen); + if (acceptsd < 0) + { + message("server: accept failure: %d\n", errno); + goto errout_with_listensd; + } + message("server: Connection accepted -- receiving\n"); + + /* Configure to "linger" until all data is sent when the socket is closed */ + +#ifdef NETTEST_HAVE_SOLINGER + ling.l_onoff = 1; + ling.l_linger = 30; /* timeout is seconds */ + if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0) + { + message("server: setsockopt SO_LINGER failure: %d\n", errno); + goto errout_with_acceptsd; + } +#endif + +#ifdef CONFIG_EXAMPLE_NETTEST_PERFORMANCE + /* Then receive data forever */ + + for (;;) + { + nbytesread = recv(acceptsd, buffer, 2*SENDSIZE, 0); + if (nbytesread <= 0) + { + message("server: recv failed: %d\n", errno); + goto errout_with_acceptsd; + } + message("Received %d bytes\n", nbytesread); + } +#else + /* Receive canned message */ + + totalbytesread = 0; + while (totalbytesread < SENDSIZE) + { + message("server: Reading...\n"); + nbytesread = recv(acceptsd, &buffer[totalbytesread], 2*SENDSIZE - totalbytesread, 0); + if (nbytesread <= 0) + { + message("server: recv failed: %d\n", errno); + goto errout_with_acceptsd; + } + + totalbytesread += nbytesread; + message("server: Received %d of %d bytes\n", totalbytesread, SENDSIZE); + } + + /* Verify the message */ + + if (totalbytesread != SENDSIZE) + { + message("server: Received %d / Expected %d bytes\n", totalbytesread, SENDSIZE); + goto errout_with_acceptsd; + } + + ch = 0x20; + for (i = 0; i < SENDSIZE; i++ ) + { + if (buffer[i] != ch) + { + message("server: Byte %d is %02x / Expected %02x\n", i, buffer[i], ch); + goto errout_with_acceptsd; + } + + if (++ch > 0x7e) + { + ch = 0x20; + } + } + + /* Then send the same data back to the client */ + + message("server: Sending %d bytes\n", totalbytesread); + nbytessent = send(acceptsd, buffer, totalbytesread, 0); + if (nbytessent <= 0) + { + message("server: send failed: %d\n", errno); + goto errout_with_acceptsd; + } + message("server: Sent %d bytes\n", nbytessent); + + /* If this platform only does abortive disconnects, then wait a bit to get the + * client side a change to receive the data. + */ + +#if 1 /* Do it for all platforms */ + message("server: Wait before closing\n"); + sleep(60); +#endif + + close(listensd); + close(acceptsd); + free(buffer); + return; +#endif + +errout_with_acceptsd: + close(acceptsd); + +errout_with_listensd: + close(listensd); + +errout_with_buffer: + free(buffer); + exit(1); +} diff --git a/apps/examples/nsh/Makefile b/apps/examples/nsh/Makefile new file mode 100644 index 000000000..b5844f9ed --- /dev/null +++ b/apps/examples/nsh/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/examples/nsh/Makefile +# +# Copyright (C) 2007-2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttShell (NSH) Example + +ASRCS = +CSRCS = nsh_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/nsh/nsh_main.c b/apps/examples/nsh/nsh_main.c new file mode 100644 index 000000000..53235a835 --- /dev/null +++ b/apps/examples/nsh/nsh_main.c @@ -0,0 +1,136 @@ +/**************************************************************************** + * examples/nsh/nsh_main.c + * + * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/stat.h> +#include <stdint.h> +#include <stdio.h> +#include <sched.h> +#include <errno.h> + +#include <apps/nsh.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + int mid_priority; +#if defined(CONFIG_NSH_CONSOLE) && defined(CONFIG_NSH_TELNET) + int ret; +#endif + + /* Initialize the NSH library */ + + nsh_initialize(); + + /* Set the priority of this task to something in the middle so that 'nice' + * can both raise and lower the priority. + */ + + mid_priority = (sched_get_priority_max(SCHED_NSH) + sched_get_priority_min(SCHED_NSH)) >> 1; + { + struct sched_param param; + + param.sched_priority = mid_priority; + (void)sched_setscheduler(0, SCHED_NSH, ¶m); + } + + /* If both the console and telnet are selected as front-ends, then run + * the telnet front end on another thread. + */ + +#if defined(CONFIG_NSH_CONSOLE) && defined(CONFIG_NSH_TELNET) +# ifndef CONFIG_CUSTOM_STACK + ret = task_create("nsh_telnetmain", mid_priority, CONFIG_NSH_STACKSIZE, + nsh_telnetmain, NULL); +# else + ret = task_create("nsh_telnetmain", mid_priority, nsh_telnetmain, NULL); +# endif + if (ret < 0) + { + /* The daemon is NOT running. Report the the error then fail... + * either with the serial console up or just exiting. + */ + + fprintf(stderr, "ERROR: Failed to start TELNET daemon: %d\n", errno); + } + + /* If only the telnet front-end is selected, run it on this thread */ + +#elif defined(CONFIG_NSH_TELNET) + return nsh_telnetmain(0, NULL); +#endif + +/* If the serial console front end is selected, then run it on this thread */ + +#ifdef CONFIG_NSH_CONSOLE + return nsh_consolemain(0, NULL); +#endif +} diff --git a/apps/examples/null/Makefile b/apps/examples/null/Makefile new file mode 100644 index 000000000..3938eb171 --- /dev/null +++ b/apps/examples/null/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# examples/null/Makefile +# +# Copyright (C) 2007-2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# The smallest thing you can build -- the NULL example. + +ASRCS = +CSRCS = null_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/null/null_main.c b/apps/examples/null/null_main.c new file mode 100644 index 000000000..10fc1bf1e --- /dev/null +++ b/apps/examples/null/null_main.c @@ -0,0 +1,67 @@ +/**************************************************************************** + * examples/null/null_main.c + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + return 0; +} diff --git a/apps/examples/nx/Makefile b/apps/examples/nx/Makefile new file mode 100644 index 000000000..bdeb57e22 --- /dev/null +++ b/apps/examples/nx/Makefile @@ -0,0 +1,108 @@ +############################################################################ +# apps/examples/nx/Makefile +# +# Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttX NX Graphics Example. + +ASRCS = +CSRCS = nx_main.c nx_events.c nx_kbdin.c +ifeq ($(CONFIG_NX_MULTIUSER),y) +CSRCS += nx_server.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# NX built-in application info + +APPNAME = nx +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_NX_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/nx/nx_events.c b/apps/examples/nx/nx_events.c new file mode 100644 index 000000000..29fe5fb8a --- /dev/null +++ b/apps/examples/nx/nx_events.c @@ -0,0 +1,337 @@ +/**************************************************************************** + * examples/nx/nx_events.c + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <semaphore.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxtk.h> +#include "nx_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void nxeg_redraw(NXEGWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool morem, FAR void *arg); +static void nxeg_position(NXEGWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg); +#ifdef CONFIG_NX_MOUSE +static void nxeg_mousein(NXEGWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg); +#endif + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +static void nxeg_tbredraw(NXEGWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool morem, FAR void *arg); +static void nxeg_tbposition(NXEGWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg); +#ifdef CONFIG_NX_MOUSE +static void nxeg_tbmousein(NXEGWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg); +#endif +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct nx_callback_s g_nxcb = +{ + nxeg_redraw, /* redraw */ + nxeg_position /* position */ +#ifdef CONFIG_NX_MOUSE + , nxeg_mousein /* mousein */ +#endif +#ifdef CONFIG_NX_KBD + , nxeg_kbdin /* my kbdin */ +#endif +}; + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +const struct nx_callback_s g_tbcb = +{ + nxeg_tbredraw, /* redraw */ + nxeg_tbposition /* position */ +#ifdef CONFIG_NX_MOUSE + , nxeg_tbmousein /* mousein */ +#endif +#ifdef CONFIG_NX_KBD + , nxeg_tbkbdin /* my kbdin */ +#endif +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxeg_fillwindow + ****************************************************************************/ + +static inline void nxeg_fillwindow(NXEGWINDOW hwnd, + FAR const struct nxgl_rect_s *rect, + FAR struct nxeg_state_s *st) +{ + int ret; + +#ifdef CONFIG_EXAMPLES_NX_RAWWINDOWS + ret = nx_fill(hwnd, rect, st->color); + if (ret < 0) + { + message("nxeg_fillwindow: nx_fill failed: %d\n", errno); + } +#else + ret = nxtk_fillwindow(hwnd, rect, st->color); + if (ret < 0) + { + message("nxeg_fillwindow: nxtk_fillwindow failed: %d\n", errno); + } +#endif +#ifdef CONFIG_NX_KBD + nxeg_filltext(hwnd, rect, st); +#endif +} + +/**************************************************************************** + * Name: nxeg_fillwindow + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +static inline void nxeg_filltoolbar(NXTKWINDOW htb, + FAR const struct nxgl_rect_s *rect, + nxgl_mxpixel_t color[CONFIG_NX_NPLANES]) +{ + int ret; + + ret = nxtk_filltoolbar(htb, rect, color); + if (ret < 0) + { + message("nxeg_filltoolbar: nxtk_filltoolbar failed: %d\n", errno); + } +} +#endif + +/**************************************************************************** + * Name: nxeg_redraw + ****************************************************************************/ + +static void nxeg_redraw(NXEGWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool more, FAR void *arg) +{ + FAR struct nxeg_state_s *st = (FAR struct nxeg_state_s *)arg; + message("nxeg_redraw%d: hwnd=%p rect={(%d,%d),(%d,%d)} more=%s\n", + st->wnum, hwnd, + rect->pt1.x, rect->pt1.y, rect->pt2.x, rect->pt2.y, + more ? "true" : "false"); + + nxeg_fillwindow(hwnd, rect, st); +} + +/**************************************************************************** + * Name: nxeg_position + ****************************************************************************/ + +static void nxeg_position(NXEGWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg) +{ + FAR struct nxeg_state_s *st = (FAR struct nxeg_state_s *)arg; + + /* Report the position */ + + message("nxeg_position%d: hwnd=%p size=(%d,%d) pos=(%d,%d) bounds={(%d,%d),(%d,%d)}\n", + st->wnum, hwnd, size->w, size->h, pos->x, pos->y, + bounds->pt1.x, bounds->pt1.y, bounds->pt2.x, bounds->pt2.y); + + /* Have we picked off the window bounds yet? */ + + if (!b_haveresolution) + { + /* Save the window limits (these should be the same for all places and all windows */ + + g_xres = bounds->pt2.x; + g_yres = bounds->pt2.y; + + b_haveresolution = true; + sem_post(&g_semevent); + message("nxeg_position2: Have xres=%d yres=%d\n", g_xres, g_yres); + } +} + +/**************************************************************************** + * Name: nxeg_mousein + ****************************************************************************/ + +#ifdef CONFIG_NX_MOUSE +static void nxeg_mousein(NXEGWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg) +{ + FAR struct nxeg_state_s *st = (FAR struct nxeg_state_s *)arg; + message("nxeg_mousein%d: hwnd=%p pos=(%d,%d) button=%02x\n", + st->wnum, hwnd, pos->x, pos->y, buttons); +} +#endif + +/**************************************************************************** + * Name: nxeg_tbredraw + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +static void nxeg_tbredraw(NXEGWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool more, FAR void *arg) +{ + FAR struct nxeg_state_s *st = (FAR struct nxeg_state_s *)arg; + message("nxeg_tbredraw%d: hwnd=%p rect={(%d,%d),(%d,%d)} more=%s\n", + st->wnum, hwnd, + rect->pt1.x, rect->pt1.y, rect->pt2.x, rect->pt2.y, + more ? "true" : "false"); + nxeg_filltoolbar(hwnd, rect, g_tbcolor); +} +#endif + +/**************************************************************************** + * Name: nxeg_position + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +static void nxeg_tbposition(NXEGWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg) +{ + FAR struct nxeg_state_s *st = (FAR struct nxeg_state_s *)arg; + + /* Report the position */ + + message("nxeg_ptbosition%d: hwnd=%p size=(%d,%d) pos=(%d,%d) bounds={(%d,%d),(%d,%d)}\n", + st->wnum, hwnd, size->w, size->h, pos->x, pos->y, + bounds->pt1.x, bounds->pt1.y, bounds->pt2.x, bounds->pt2.y); +} +#endif + +/**************************************************************************** + * Name: nxeg_tbmousein + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +#ifdef CONFIG_NX_MOUSE +static void nxeg_tbmousein(NXEGWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg) +{ + FAR struct nxeg_state_s *st = (FAR struct nxeg_state_s *)arg; + + message("nxeg_tbmousein%d: hwnd=%p pos=(%d,%d) button=%02x\n", + st->wnum, hwnd, pos->x, pos->y, buttons); +} +#endif +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nx_listenerthread + ****************************************************************************/ + +#ifdef CONFIG_NX_MULTIUSER +FAR void *nx_listenerthread(FAR void *arg) +{ + int ret; + + /* Process events forever */ + + for (;;) + { + /* Handle the next event. If we were configured blocking, then + * we will stay right here until the next event is received. Since + * we have dedicated a while thread to servicing events, it would + * be most natural to also select CONFIG_NX_BLOCKING -- if not, the + * following would be a tight infinite loop (unless we added addition + * logic with nx_eventnotify and sigwait to pace it). + */ + + ret = nx_eventhandler(g_hnx); + if (ret < 0) + { + /* An error occurred... assume that we have lost connection with + * the server. + */ + + message("nx_listenerthread: Lost server connection: %d\n", errno); + exit(NXEXIT_LOSTSERVERCONN); + } + + /* If we received a message, we must be connected */ + + if (!g_connected) + { + g_connected = true; + sem_post(&g_semevent); + message("nx_listenerthread: Connected\n"); + } + } +} +#endif diff --git a/apps/examples/nx/nx_internal.h b/apps/examples/nx/nx_internal.h new file mode 100644 index 000000000..a0fae77a9 --- /dev/null +++ b/apps/examples/nx/nx_internal.h @@ -0,0 +1,317 @@ +/**************************************************************************** + * examples/nx/nx_internal.h + * + * Copyright (C) 2008-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_NX_NX_INTERNAL_H +#define __EXAMPLES_NX_NX_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <semaphore.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxtk.h> +#include <nuttx/nx/nxfonts.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_NX +# error "NX is not enabled (CONFIG_NX)" +#endif + +#ifndef CONFIG_EXAMPLES_NX_VPLANE +# define CONFIG_EXAMPLES_NX_VPLANE 0 +#endif + +#ifndef CONFIG_EXAMPLES_NX_BPP +# define CONFIG_EXAMPLES_NX_BPP 32 +#endif + +#ifndef CONFIG_EXAMPLES_NX_BGCOLOR +# if CONFIG_EXAMPLES_NX_BPP == 24 || CONFIG_EXAMPLES_NX_BPP == 32 +# define CONFIG_EXAMPLES_NX_BGCOLOR 0x007b68ee +# elif CONFIG_EXAMPLES_NX_BPP == 16 +# define CONFIG_EXAMPLES_NX_BGCOLOR 0x7b5d +# else +# define CONFIG_EXAMPLES_NX_BGCOLOR ' ' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NX_COLOR1 +# if CONFIG_EXAMPLES_NX_BPP == 24 || CONFIG_EXAMPLES_NX_BPP == 32 +# define CONFIG_EXAMPLES_NX_COLOR1 0x00e6e6fa +# elif CONFIG_EXAMPLES_NX_BPP == 16 +# define CONFIG_EXAMPLES_NX_COLOR1 0xe73f +# else +# define CONFIG_EXAMPLES_NX_COLOR1 '1' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NX_COLOR2 +# if CONFIG_EXAMPLES_NX_BPP == 24 || CONFIG_EXAMPLES_NX_BPP == 32 +# define CONFIG_EXAMPLES_NX_COLOR2 0x00dcdcdc +# elif CONFIG_EXAMPLES_NX_BPP == 16 +# define CONFIG_EXAMPLES_NX_COLOR2 0xdefb +# else +# define CONFIG_EXAMPLES_NX_COLOR2 '2' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NX_TBCOLOR +# if CONFIG_EXAMPLES_NX_BPP == 24 || CONFIG_EXAMPLES_NX_BPP == 32 +# define CONFIG_EXAMPLES_NX_TBCOLOR 0x00a9a9a9 +# elif CONFIG_EXAMPLES_NX_BPP == 16 +# define CONFIG_EXAMPLES_NX_TBCOLOR 0xad55 +# else +# define CONFIG_EXAMPLES_NX_TBCOLOR 'T' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NX_FONTID +# define CONFIG_EXAMPLES_NX_FONTID NXFONT_DEFAULT +#endif + +#ifndef CONFIG_EXAMPLES_NX_FONTCOLOR +# if CONFIG_EXAMPLES_NX_BPP == 24 || CONFIG_EXAMPLES_NX_BPP == 32 +# define CONFIG_EXAMPLES_NX_FONTCOLOR 0x00000000 +# elif CONFIG_EXAMPLES_NX_BPP == 16 +# define CONFIG_EXAMPLES_NX_FONTCOLOR 0x0000 +# else +# define CONFIG_EXAMPLES_NX_FONTCOLOR 'F' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NX_TOOLBAR_HEIGHT +# define CONFIG_EXAMPLES_NX_TOOLBAR_HEIGHT 16 +#endif + +#ifdef CONFIG_NX_MULTIUSER +# ifdef CONFIG_DISABLE_MQUEUE +# error "The multi-threaded example requires MQ support (CONFIG_DISABLE_MQUEUE=n)" +# endif +# ifdef CONFIG_DISABLE_SIGNALS +# error "This example requires signal support (CONFIG_DISABLE_SIGNALS=n)" +# endif +# ifdef CONFIG_DISABLE_PTHREAD +# error "This example requires pthread support (CONFIG_DISABLE_PTHREAD=n)" +# endif +# ifndef CONFIG_NX_BLOCKING +# error "This example depends on CONFIG_NX_BLOCKING" +# endif +# ifndef CONFIG_EXAMPLES_NX_STACKSIZE +# define CONFIG_EXAMPLES_NX_STACKSIZE 2048 +# endif +# ifndef CONFIG_EXAMPLES_NX_LISTENERPRIO +# define CONFIG_EXAMPLES_NX_LISTENERPRIO 100 +# endif +# ifndef CONFIG_EXAMPLES_NX_CLIENTPRIO +# define CONFIG_EXAMPLES_NX_CLIENTPRIO 100 +# endif +# ifndef CONFIG_EXAMPLES_NX_SERVERPRIO +# define CONFIG_EXAMPLES_NX_SERVERPRIO 120 +# endif +# ifndef CONFIG_EXAMPLES_NX_NOTIFYSIGNO +# define CONFIG_EXAMPLES_NX_NOTIFYSIGNO 4 +# endif +#endif + +#ifdef CONFIG_EXAMPLES_NX_RAWWINDOWS +# define NXEGWINDOW NXWINDOW +#else +# define NXEGWINDOW NXTKWINDOW +#endif + +#define NXTK_MAXKBDCHARS 16 + +/* Debug ********************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum exitcode_e +{ + NXEXIT_SUCCESS = 0, + NXEXIT_SIGPROCMASK, + NXEXIT_SCHEDSETPARAM, + NXEXIT_EVENTNOTIFY, + NXEXIT_TASKCREATE, + NXEXIT_PTHREADCREATE, + NXEXIT_EXTINITIALIZE, + NXEXIT_FBINITIALIZE, + NXEXIT_FBGETVPLANE, + NXEXIT_LCDINITIALIZE, + NXEXIT_LCDGETDEV, + NXEXIT_NXOPEN, + NXEXIT_FONTOPEN, + NXEXIT_NXOPENTOOLBAR, + NXEXIT_NXCONNECT, + NXEXIT_NXSETBGCOLOR, + NXEXIT_NXOPENWINDOW, + NXEXIT_NXSETSIZE, + NXEXIT_NXSETPOSITION, + NXEXIT_NXLOWER, + NXEXIT_NXRAISE, + NXEXIT_NXCLOSEWINDOW, + NXEXIT_LOSTSERVERCONN +}; + +/* Describes one cached glyph bitmap */ + +struct nxeg_glyph_s +{ + uint8_t code; /* Character code */ + uint8_t height; /* Height of this glyph (in rows) */ + uint8_t width; /* Width of this glyph (in pixels) */ + uint8_t stride; /* Width of the glyph row (in bytes) */ + FAR uint8_t *bitmap; /* Allocated bitmap memory */ +}; + +/* Describes on character on the display */ + +struct nxeg_bitmap_s +{ + struct nxgl_rect_s bounds; /* Size/position of bitmap */ + FAR const struct nxeg_glyph_s *glyph; /* The cached glyph */ +}; + +/* Describes the overall state of on one window */ + +struct nxeg_state_s +{ + uint8_t wnum; /* Window number */ + nxgl_mxpixel_t color[CONFIG_NX_NPLANES]; /* Window color */ + +#ifdef CONFIG_NX_KBD + uint8_t height; /* Max height of a font in pixels */ + uint8_t width; /* Max width of a font in pixels */ + uint8_t spwidth; /* The width of a space */ + + uint8_t nchars; /* Number of KBD chars received */ + uint8_t nglyphs; /* Number of glyphs cached */ + + struct nxeg_bitmap_s bm[NXTK_MAXKBDCHARS]; + struct nxeg_glyph_s glyph[NXTK_MAXKBDCHARS]; +#endif +}; + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/* The connecton handle */ + +extern NXHANDLE g_hnx; + +/* NX callback vtables */ + +extern const struct nx_callback_s g_nxcb; +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +extern const struct nx_callback_s g_tbcb; +#endif + +/* The font handle */ + +extern NXHANDLE g_fonthandle; + +/* The screen resolution */ + +extern nxgl_coord_t g_xres; +extern nxgl_coord_t g_yres; + +extern bool b_haveresolution; +#ifdef CONFIG_NX_MULTIUSER +extern bool g_connected; +#endif +extern sem_t g_semevent; + +/* Colors used to fill window 1 & 2 */ + +extern nxgl_mxpixel_t g_color1[CONFIG_NX_NPLANES]; +extern nxgl_mxpixel_t g_color2[CONFIG_NX_NPLANES]; +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +extern nxgl_mxpixel_t g_tbcolor[CONFIG_NX_NPLANES]; +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NX_EXTERNINIT +extern FAR NX_DRIVERTYPE *up_nxdrvinit(unsigned int devno); +#endif + +#if defined(CONFIG_NX) && defined(CONFIG_NX_MULTIUSER) +extern int nx_servertask(int argc, char *argv[]); +extern FAR void *nx_listenerthread(FAR void *arg); +#endif + +#ifdef CONFIG_NX_KBD +extern void nxeg_kbdin(NXWINDOW hwnd, uint8_t nch, const uint8_t *ch, FAR void *arg); +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +extern void nxeg_tbkbdin(NXWINDOW hwnd, uint8_t nch, const uint8_t *ch, FAR void *arg); +#endif +extern void nxeg_filltext(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + FAR struct nxeg_state_s *st); +#endif + +#endif /* __EXAMPLES_NX_NX_INTERNAL_H */ diff --git a/apps/examples/nx/nx_kbdin.c b/apps/examples/nx/nx_kbdin.c new file mode 100644 index 000000000..ebb1ef791 --- /dev/null +++ b/apps/examples/nx/nx_kbdin.c @@ -0,0 +1,467 @@ +/**************************************************************************** + * examples/nx/nx_kbdin.c + * + * Copyright (C) 2008, 2010-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxtk.h> +#include <nuttx/nx/nxfonts.h> + +#include "nx_internal.h" + +#ifdef CONFIG_NX_KBD + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Select renderer -- Some additional logic would be required to support + * pixel depths that are not directly addressable (1,2,4, and 24). + */ + +#if CONFIG_EXAMPLES_NX_BPP == 1 +# define RENDERER nxf_convert_1bpp +#elif CONFIG_EXAMPLES_NX_BPP == 2 +# define RENDERER nxf_convert_2bpp +#elif CONFIG_EXAMPLES_NX_BPP == 4 +# define RENDERER nxf_convert_4bpp +#elif CONFIG_EXAMPLES_NX_BPP == 8 +# define RENDERER nxf_convert_8bpp +#elif CONFIG_EXAMPLES_NX_BPP == 16 +# define RENDERER nxf_convert_16bpp +#elif CONFIG_EXAMPLES_NX_BPP == 24 +# define RENDERER nxf_convert_24bpp +#elif CONFIG_EXAMPLES_NX_BPP == 32 +# define RENDERER nxf_convert_32bpp +#else +# error "Unsupported CONFIG_EXAMPLES_NX_BPP" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxeg_fillchar + ****************************************************************************/ + +static void nxeg_fillchar(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + FAR const struct nxeg_bitmap_s *bm) +{ + FAR void *src = (FAR void *)bm->glyph->bitmap; + struct nxgl_rect_s intersection; + int ret; + + /* Handle the special case of spaces which have no glyph bitmap */ + + if (src) + { + /* Get the intersection of the redraw region and the character bitmap */ + + nxgl_rectintersect(&intersection, rect, &bm->bounds); + if (!nxgl_nullrect(&intersection)) + { +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS + ret = nxtk_bitmapwindow((NXTKWINDOW)hwnd, &intersection, (FAR const void **)&src, + &bm->bounds.pt1, + (unsigned int)bm->glyph->stride); + if (ret < 0) + { + message("nxeg_fillchar: nxtk_bitmapwindow failed: %d\n", errno); + } +#else + ret = nx_bitmap((NXWINDOW)hwnd, &intersection, &src, + &bm->bounds.pt1, + (unsigned int)bm->glyph->stride); + if (ret < 0) + { + message("nxeg_fillchar: nx_bitmapwindow failed: %d\n", errno); + } +#endif + } + } +} + +/**************************************************************************** + * Name: nxeg_renderglyph + ****************************************************************************/ + +static inline FAR const struct nxeg_glyph_s * +nxeg_renderglyph(FAR struct nxeg_state_s *st, + FAR const struct nx_fontbitmap_s *bm, uint8_t ch) +{ + FAR struct nxeg_glyph_s *glyph = NULL; + FAR nxgl_mxpixel_t *ptr; +#if CONFIG_EXAMPLES_NX_BPP < 8 + nxgl_mxpixel_t pixel; +#endif + int bmsize; + int row; + int col; + int ret; + + /* Make sure that there is room for another glyph */ + + message("nxeg_renderglyph: ch=%02x\n", ch); + if (st->nglyphs < NXTK_MAXKBDCHARS) + { + /* Allocate the glyph */ + + glyph = &st->glyph[st->nglyphs]; + glyph->code = ch; + + /* Get the dimensions of the glyph */ + + glyph->width = bm->metric.width + bm->metric.xoffset; + glyph->height = bm->metric.height + bm->metric.yoffset; + + /* Allocate memory to hold the glyph with its offsets */ + + glyph->stride = (glyph->width * CONFIG_EXAMPLES_NX_BPP + 7) / 8; + bmsize = glyph->stride * glyph->height; + glyph->bitmap = (FAR uint8_t *)malloc(bmsize); + + if (glyph->bitmap) + { + /* Initialize the glyph memory to the background color */ + +#if CONFIG_EXAMPLES_NX_BPP < 8 + pixel = st->color[0]; +# if CONFIG_EXAMPLES_NX_BPP == 1 + /* Pack 1-bit pixels into a 2-bits */ + + pixel &= 0x01; + pixel = (pixel) << 1 |pixel; +# endif +# if CONFIG_EXAMPLES_NX_BPP < 4 + /* Pack 2-bit pixels into a nibble */ + + pixel &= 0x03; + pixel = (pixel) << 2 |pixel; +# endif + + /* Pack 4-bit nibbles into a byte */ + + pixel &= 0x0f; + pixel = (pixel) << 4 | pixel; + + ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; + for (row = 0; row < glyph->height; row++) + { + for (col = 0; col < glyph->stride; col++) + { + /* Transfer the packed bytes into the buffer */ + + *ptr++ = pixel; + } + } + +#elif CONFIG_EXAMPLES_NX_BPP == 24 +# error "Additional logic is needed here for 24bpp support" + +#else /* CONFIG_EXAMPLES_NX_BPP = {8,16,32} */ + + ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; + for (row = 0; row < glyph->height; row++) + { + /* Just copy the color value into the glyph memory */ + + for (col = 0; col < glyph->width; col++) + { + *ptr++ = st->color[0]; + } + } +#endif + + /* Then render the glyph into the allocated memory */ + + ret = RENDERER((FAR nxgl_mxpixel_t*)glyph->bitmap, + glyph->height, glyph->width, glyph->stride, + bm, CONFIG_EXAMPLES_NX_FONTCOLOR); + if (ret < 0) + { + /* Actually, the RENDERER never returns a failure */ + + message("nxeg_renderglyph: RENDERER failed\n"); + free(glyph->bitmap); + glyph->bitmap = NULL; + glyph = NULL; + } + else + { + /* Make it permanent */ + + st->nglyphs++; + } + } + } + + return glyph; +} + +/**************************************************************************** + * Name: nxeg_addspace + ****************************************************************************/ + +static inline FAR const struct nxeg_glyph_s * +nxeg_addspace(FAR struct nxeg_state_s *st, uint8_t ch) +{ + FAR struct nxeg_glyph_s *glyph = NULL; + + /* Make sure that there is room for another glyph */ + + if (st->nglyphs < NXTK_MAXKBDCHARS) + { + /* Allocate the NULL glyph */ + + glyph = &st->glyph[st->nglyphs]; + memset(glyph, 0, sizeof(struct nxeg_glyph_s)); + + glyph->code = ' '; + glyph->width = st->spwidth; + + st->nglyphs++; + } + return glyph; +} + +/**************************************************************************** + * Name: nxeg_findglyph + ****************************************************************************/ + +static FAR const struct nxeg_glyph_s * +nxeg_findglyph(FAR struct nxeg_state_s *st, uint8_t ch) +{ + int i; + + /* First, try to find the glyph in the cache of pre-rendered glyphs */ + + for (i = 0; i < st->nglyphs; i++) + { + if (st->glyph[i].code == ch) + { + return &st->glyph[i]; + } + } + return NULL; +} + +/**************************************************************************** + * Name: nxeg_getglyph + ****************************************************************************/ + +static FAR const struct nxeg_glyph_s * +nxeg_getglyph(FAR struct nxeg_state_s *st, uint8_t ch) +{ + FAR const struct nxeg_glyph_s *glyph; + FAR const struct nx_fontbitmap_s *bm; + + /* First, try to find the glyph in the cache of pre-rendered glyphs */ + + glyph = nxeg_findglyph(st, ch); + if (!glyph) + { + /* No, it is not cached... Does the code map to a glyph? */ + + bm = nxf_getbitmap(g_fonthandle, ch); + if (!bm) + { + /* No, there is no glyph for this code. Use space */ + + glyph = nxeg_findglyph(st, ' '); + if (!glyph) + { + /* There isn't fake glyph for ' ' yet... create one */ + + glyph = nxeg_addspace(st, ' '); + } + } + else + { + glyph = nxeg_renderglyph(st, bm, ch); + } + } + return glyph; +} + +/**************************************************************************** + * Name: nxeg_addchar + ****************************************************************************/ + +static FAR const struct nxeg_bitmap_s * +nxeg_addchar(FAR struct nxeg_state_s *st, uint8_t ch) +{ + FAR struct nxeg_bitmap_s *bm = NULL; + FAR struct nxeg_bitmap_s *bmleft; + nxgl_coord_t leftx; + + /* Is there space for another character on the display? */ + + if (st->nchars < NXTK_MAXKBDCHARS) + { + /* Yes, setup the bitmap */ + + bm = &st->bm[st->nchars]; + + /* Find the matching glyph */ + + bm->glyph = nxeg_getglyph(st, ch); + if (!bm->glyph) + { + return NULL; + } + + /* Set up the bounds for the bitmap */ + + if (st->nchars <= 0) + { + /* The first character is one space from the left */ + + leftx = st->spwidth; + } + else + { + /* Otherwise, it is to the left of the preceding char */ + + bmleft = &st->bm[st->nchars-1]; + leftx = bmleft->bounds.pt2.x + 1; + } + + bm->bounds.pt1.x = leftx; + bm->bounds.pt1.y = 2; + bm->bounds.pt2.x = leftx + bm->glyph->width - 1; + bm->bounds.pt2.y = 2 + bm->glyph->height - 1; + + st->nchars++; + } + return bm; +} + +/**************************************************************************** + * Name: nxeg_addchars + ****************************************************************************/ + +static inline void nxeg_addchars(NXWINDOW hwnd, FAR struct nxeg_state_s *st, + uint8_t nch, FAR const uint8_t *ch) +{ + FAR const struct nxeg_bitmap_s *bm; + + while (nch--) + { + bm = nxeg_addchar(st, *ch++); + if (bm) + { + nxeg_fillchar(hwnd, &bm->bounds, bm); + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxeg_kbdin + ****************************************************************************/ + +void nxeg_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg) +{ + FAR struct nxeg_state_s *st = (FAR struct nxeg_state_s *)arg; + message("nxeg_kbdin%d: hwnd=%p nch=%d\n", st->wnum, hwnd, nch); + nxeg_addchars(hwnd, st, nch, ch); +} + +/**************************************************************************** + * Name: nxeg_tbkbdin + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +void nxeg_tbkbdin(NXWINDOW hwnd, uint8_t nch, const uint8_t *ch, FAR void *arg) +{ + FAR struct nxeg_state_s *st = (FAR struct nxeg_state_s *)arg; + message("nxeg_tbkbdin: ERROR -- toolbar should not received keyboard input\n"); + message("nxeg_tbkbdin%d: hwnd=%p nch=%d\n", st->wnum, hwnd, nch); +} +#endif + +/**************************************************************************** + * Name: nxeg_filltext + ****************************************************************************/ + +void nxeg_filltext(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + FAR struct nxeg_state_s *st) +{ + int i; + + /* Fill each character on the display (Only the characters within rect + * will actually be redrawn). + */ + + for (i = 0; i < st->nchars; i++) + { + nxeg_fillchar(hwnd, rect, &st->bm[i]); + } +} + +#endif /* CONFIG_NX_KBD */ diff --git a/apps/examples/nx/nx_main.c b/apps/examples/nx/nx_main.c new file mode 100644 index 000000000..db17ea2f2 --- /dev/null +++ b/apps/examples/nx/nx_main.c @@ -0,0 +1,908 @@ +/**************************************************************************** + * examples/nx/nx_main.c + * + * Copyright (C) 2008-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sched.h> +#include <pthread.h> +#include <errno.h> +#include <debug.h> + +#ifdef CONFIG_NX_LCDDRIVER +# include <nuttx/lcd/lcd.h> +#else +# include <nuttx/fb.h> +#endif + +#include <nuttx/arch.h> +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxtk.h> +#include <nuttx/nx/nxfonts.h> + +#include "nx_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ +/* If not specified, assume that the hardware supports one video plane */ + +#ifndef CONFIG_EXAMPLES_NX_VPLANE +# define CONFIG_EXAMPLES_NX_VPLANE 0 +#endif + +/* If not specified, assume that the hardware supports one LCD device */ + +#ifndef CONFIG_EXAMPLES_NX_DEVNO +# define CONFIG_EXAMPLES_NX_DEVNO 0 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static int g_exitcode = NXEXIT_SUCCESS; + +static struct nxeg_state_s g_wstate[2]; + +#ifdef CONFIG_NX_KBD +static const uint8_t g_kbdmsg1[] = "NuttX is cool!"; +static const uint8_t g_kbdmsg2[] = "NuttX is fun!"; +#endif + +/* The font handle */ + +NXHANDLE g_fonthandle; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* The connecton handler */ + +NXHANDLE g_hnx = NULL; + +/* The screen resolution */ + +nxgl_coord_t g_xres; +nxgl_coord_t g_yres; + +bool b_haveresolution = false; +#ifdef CONFIG_NX_MULTIUSER +bool g_connected = false; +#endif +sem_t g_semevent = {0}; + +/* Colors used to fill window 1 & 2 */ + +nxgl_mxpixel_t g_color1[CONFIG_NX_NPLANES]; +nxgl_mxpixel_t g_color2[CONFIG_NX_NPLANES]; +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +nxgl_mxpixel_t g_tbcolor[CONFIG_NX_NPLANES]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxeg_drivemouse + ****************************************************************************/ + +#ifdef CONFIG_NX_MOUSE +static void nxeg_drivemouse(void) +{ + nxgl_coord_t x; + nxgl_coord_t y; + nxgl_coord_t xstep = g_xres / 8; + nxgl_coord_t ystep = g_yres / 8; + + for (x = 0; x < g_xres; x += xstep) + { + for (y = 0; y < g_yres; y += ystep) + { + message("nxeg_drivemouse: Mouse left button at (%d,%d)\n", x, y); + (void)nx_mousein(g_hnx, x, y, NX_MOUSE_LEFTBUTTON); + } + } +} +#endif + +/**************************************************************************** + * Name: nxeg_initstate + ****************************************************************************/ + +static void nxeg_initstate(FAR struct nxeg_state_s *st, int wnum, + nxgl_mxpixel_t color) +{ +#ifdef CONFIG_NX_KBD + FAR const struct nx_font_s *fontset; +#endif + + /* Initialize the window number (used for debug output only) and color + * (used for redrawing the window) + */ + + st->wnum = wnum; + st->color[0] = color; + + /* Get information about the font set being used and save this in the + * state structure + */ + +#ifdef CONFIG_NX_KBD + fontset = nxf_getfontset(g_fonthandle); + st->nchars = 0; + st->nglyphs = 0; + st->height = fontset->mxheight; + st->width = fontset->mxwidth; + st->spwidth = fontset->spwidth; +#endif +} + +/**************************************************************************** + * Name: nxeg_freestate + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +static void nxeg_freestate(FAR struct nxeg_state_s *st) +{ +#ifdef CONFIG_NX_KBD + int i; + + if (st) + { + for (i = 0; i < st->nglyphs; i++) + { + if (st->glyph[i].bitmap) + { + free(st->glyph[i].bitmap); + } + st->glyph[i].bitmap = NULL; + } + st->nchars = 0; + } +#endif +} +#endif + +/**************************************************************************** + * Name: nxeg_openwindow + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NX_RAWWINDOWS +static inline NXEGWINDOW nxeg_openwindow(FAR const struct nx_callback_s *cb, + FAR struct nxeg_state_s *state) +{ + NXEGWINDOW hwnd; + + hwnd = nx_openwindow(g_hnx, cb, (FAR void *)state); + if (!hwnd) + { + message("nxeg_openwindow: nx_openwindow failed: %d\n", errno); + g_exitcode = NXEXIT_NXOPENWINDOW; + } + return hwnd; +} +#else +static inline NXEGWINDOW nxeg_openwindow(FAR const struct nx_callback_s *cb, + FAR struct nxeg_state_s *state) +{ + NXEGWINDOW hwnd; + + hwnd = nxtk_openwindow(g_hnx, cb, (FAR void *)state); + if (!hwnd) + { + message("nxeg_openwindow: nxtk_openwindow failed: %d\n", errno); + g_exitcode = NXEXIT_NXOPENWINDOW; + } + return hwnd; +} +#endif + +/**************************************************************************** + * Name: nxeg_closewindow + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NX_RAWWINDOWS +static inline int nxeg_closewindow(NXEGWINDOW hwnd, FAR struct nxeg_state_s *state) +{ + int ret = nx_closewindow(hwnd); + if (ret < 0) + { + message("nxeg_closewindow: nx_closewindow failed: %d\n", errno); + g_exitcode = NXEXIT_NXCLOSEWINDOW; + } + return ret; +} +#else +static inline int nxeg_closewindow(NXEGWINDOW hwnd, FAR struct nxeg_state_s *state) +{ + int ret = nxtk_closewindow(hwnd); + if (ret < 0) + { + message("nxeg_closewindow: nxtk_closewindow failed: %d\n", errno); + g_exitcode = NXEXIT_NXCLOSEWINDOW; + } + nxeg_freestate(state); + return ret; +} +#endif + +/**************************************************************************** + * Name: nxeg_setsize + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NX_RAWWINDOWS +static inline int nxeg_setsize(NXEGWINDOW hwnd, FAR struct nxgl_size_s *size) +{ + int ret = nx_setsize(hwnd, size); + if (ret < 0) + { + message("nxeg_setsize: nx_setsize failed: %d\n", errno); + g_exitcode = NXEXIT_NXSETSIZE; + } + return ret; +} +#else +static inline int nxeg_setsize(NXEGWINDOW hwnd, FAR struct nxgl_size_s *size) +{ + int ret = nxtk_setsize(hwnd, size); + if (ret < 0) + { + message("nxeg_setsize: nxtk_setsize failed: %d\n", errno); + g_exitcode = NXEXIT_NXSETSIZE; + } + return ret; +} +#endif + +/**************************************************************************** + * Name: nxeg_setposition + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NX_RAWWINDOWS +static inline int nxeg_setposition(NXEGWINDOW hwnd, FAR struct nxgl_point_s *pos) +{ + int ret = nx_setposition(hwnd, pos); + if (ret < 0) + { + message("nxeg_setposition: nx_setposition failed: %d\n", errno); + g_exitcode = NXEXIT_NXSETPOSITION; + } + return ret; +} +#else +static inline int nxeg_setposition(NXEGWINDOW hwnd, FAR struct nxgl_point_s *pos) +{ + int ret = nxtk_setposition(hwnd, pos); + if (ret < 0) + { + message("nxeg_setposition: nxtk_setposition failed: %d\n", errno); + g_exitcode = NXEXIT_NXSETPOSITION; + } + return ret; +} +#endif + +/**************************************************************************** + * Name: nxeq_opentoolbar + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS +static inline int nxeq_opentoolbar(NXEGWINDOW hwnd, nxgl_coord_t height, + FAR const struct nx_callback_s *cb, + FAR struct nxeg_state_s *state) +{ + int ret; + ret = nxtk_opentoolbar(hwnd, height, cb, (FAR void *)state); + if (ret < 0) + { + message("nxeq_opentoolbar: nxtk_opentoolbar failed: %d\n", errno); + g_exitcode = NXEXIT_NXOPENTOOLBAR; + } + return ret; +} +#endif + +/**************************************************************************** + * Name: nxeg_lower + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NX_RAWWINDOWS +static inline int nxeg_lower(NXEGWINDOW hwnd) +{ + int ret = nx_lower(hwnd); + if (ret < 0) + { + message("nxeg_lower: nx_lower failed: %d\n", errno); + g_exitcode = NXEXIT_NXLOWER; + } + return ret; +} +#else +static inline int nxeg_lower(NXEGWINDOW hwnd) +{ + int ret = nxtk_lower(hwnd); + if (ret < 0) + { + message("nxeg_lower: nxtk_lower failed: %d\n", errno); + g_exitcode = NXEXIT_NXLOWER; + } + return ret; +} +#endif + +/**************************************************************************** + * Name: nxeg_raise + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NX_RAWWINDOWS +static inline int nxeg_raise(NXEGWINDOW hwnd) +{ + int ret = nx_raise(hwnd); + if (ret < 0) + { + message("nxeg_raise: nx_raise failed: %d\n", errno); + g_exitcode = NXEXIT_NXRAISE; + } + return ret; +} +#else +static inline int nxeg_raise(NXEGWINDOW hwnd) +{ + int ret = nxtk_raise(hwnd); + if (ret < 0) + { + message("nxeg_raise: nxtk_raise failed: %d\n", errno); + g_exitcode = NXEXIT_NXRAISE; + } + return ret; +} +#endif + +/**************************************************************************** + * Name: nxeg_suinitialize + ****************************************************************************/ + +#ifndef CONFIG_NX_MULTIUSER +static inline int nxeg_suinitialize(void) +{ + FAR NX_DRIVERTYPE *dev; + +#if defined(CONFIG_EXAMPLES_NX_EXTERNINIT) + /* Use external graphics driver initialization */ + + message("nxeg_initialize: Initializing external graphics device\n"); + dev = up_nxdrvinit(CONFIG_EXAMPLES_NX_DEVNO); + if (!dev) + { + message("nxeg_initialize: up_nxdrvinit failed, devno=%d\n", CONFIG_EXAMPLES_NX_DEVNO); + g_exitcode = NXEXIT_EXTINITIALIZE; + return ERROR; + } + +#elif defined(CONFIG_NX_LCDDRIVER) + int ret; + + /* Initialize the LCD device */ + + message("nxeg_initialize: Initializing LCD\n"); + ret = up_lcdinitialize(); + if (ret < 0) + { + message("nxeg_initialize: up_lcdinitialize failed: %d\n", -ret); + g_exitcode = NXEXIT_LCDINITIALIZE; + return ERROR; + } + + /* Get the device instance */ + + dev = up_lcdgetdev(CONFIG_EXAMPLES_NX_DEVNO); + if (!dev) + { + message("nxeg_initialize: up_lcdgetdev failed, devno=%d\n", CONFIG_EXAMPLES_NX_DEVNO); + g_exitcode = NXEXIT_LCDGETDEV; + return ERROR; + } + + /* Turn the LCD on at 75% power */ + + (void)dev->setpower(dev, ((3*CONFIG_LCD_MAXPOWER + 3)/4)); +#else + int ret; + + /* Initialize the frame buffer device */ + + message("nxeg_initialize: Initializing framebuffer\n"); + ret = up_fbinitialize(); + if (ret < 0) + { + message("nxeg_initialize: up_fbinitialize failed: %d\n", -ret); + g_exitcode = NXEXIT_FBINITIALIZE; + return ERROR; + } + + dev = up_fbgetvplane(CONFIG_EXAMPLES_NX_VPLANE); + if (!dev) + { + message("nxeg_initialize: up_fbgetvplane failed, vplane=%d\n", CONFIG_EXAMPLES_NX_VPLANE); + g_exitcode = NXEXIT_FBGETVPLANE; + return ERROR; + } +#endif + + /* Then open NX */ + + message("nxeg_initialize: Open NX\n"); + g_hnx = nx_open(dev); + if (!g_hnx) + { + message("nxeg_suinitialize: nx_open failed: %d\n", errno); + g_exitcode = NXEXIT_NXOPEN; + return ERROR; + } + return OK; +} +#endif + +/**************************************************************************** + * Name: nxeg_initialize + ****************************************************************************/ + +#ifdef CONFIG_NX_MULTIUSER +static inline int nxeg_muinitialize(void) +{ + struct sched_param param; + pthread_t thread; + pid_t servrid; + int ret; + + /* Set the client task priority */ + + param.sched_priority = CONFIG_EXAMPLES_NX_CLIENTPRIO; + ret = sched_setparam(0, ¶m); + if (ret < 0) + { + message("nxeg_initialize: sched_setparam failed: %d\n" , ret); + g_exitcode = NXEXIT_SCHEDSETPARAM; + return ERROR; + } + + /* Start the server task */ + + message("nxeg_initialize: Starting nx_servertask task\n"); + servrid = task_create("NX Server", CONFIG_EXAMPLES_NX_SERVERPRIO, + CONFIG_EXAMPLES_NX_STACKSIZE, nx_servertask, NULL); + if (servrid < 0) + { + message("nxeg_initialize: Failed to create nx_servertask task: %d\n", errno); + g_exitcode = NXEXIT_TASKCREATE; + return ERROR; + } + + /* Wait a bit to let the server get started */ + + sleep(1); + + /* Connect to the server */ + + g_hnx = nx_connect(); + if (g_hnx) + { + pthread_attr_t attr; + + /* Start a separate thread to listen for server events. This is probably + * the least efficient way to do this, but it makes this example flow more + * smoothly. + */ + + (void)pthread_attr_init(&attr); + param.sched_priority = CONFIG_EXAMPLES_NX_LISTENERPRIO; + (void)pthread_attr_setschedparam(&attr, ¶m); + (void)pthread_attr_setstacksize(&attr, CONFIG_EXAMPLES_NX_STACKSIZE); + + ret = pthread_create(&thread, &attr, nx_listenerthread, NULL); + if (ret != 0) + { + printf("nxeg_initialize: pthread_create failed: %d\n", ret); + g_exitcode = NXEXIT_PTHREADCREATE; + return ERROR; + } + + /* Don't return until we are connected to the server */ + + while (!g_connected) + { + /* Wait for the listener thread to wake us up when we really + * are connected. + */ + + (void)sem_wait(&g_semevent); + } + } + else + { + message("nxeg_initialize: nx_connect failed: %d\n", errno); + g_exitcode = NXEXIT_NXCONNECT; + return ERROR; + } + return OK; +} +#endif + +/**************************************************************************** + * Name: nxeg_initialize + ****************************************************************************/ + +static int nxeg_initialize(void) +{ + int i; + + /* Initialize window colors */ + + for (i = 0; i < CONFIG_NX_NPLANES; i++) + { + g_color1[i] = CONFIG_EXAMPLES_NX_COLOR1; + g_color2[i] = CONFIG_EXAMPLES_NX_COLOR2; +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS + g_tbcolor[i] = CONFIG_EXAMPLES_NX_TBCOLOR; +#endif + } + +#ifdef CONFIG_NX_MULTIUSER + return nxeg_muinitialize(); +#else + return nxeg_suinitialize(); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start/nx_main + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NX_BUILTIN +# define MAIN_NAME nx_main +# define MAIN_NAME_STRING "nx_main" +#else +# define MAIN_NAME user_start +# define MAIN_NAME_STRING "user_start" +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + NXEGWINDOW hwnd1; + NXEGWINDOW hwnd2; + struct nxgl_size_s size; + struct nxgl_point_s pt; + nxgl_mxpixel_t color; + int ret; + + /* Initialize */ + + ret = nxeg_initialize(); + message(MAIN_NAME_STRING ": NX handle=%p\n", g_hnx); + if (!g_hnx || ret < 0) + { + message(MAIN_NAME_STRING ": Failed to get NX handle: %d\n", errno); + g_exitcode = NXEXIT_NXOPEN; + goto errout; + } + + /* Get the default font handle */ + + g_fonthandle = nxf_getfonthandle(CONFIG_EXAMPLES_NX_FONTID); + if (!g_fonthandle) + { + message(MAIN_NAME_STRING ": Failed to get font handle: %d\n", errno); + g_exitcode = NXEXIT_FONTOPEN; + goto errout; + } + + /* Set the background to the configured background color */ + + message(MAIN_NAME_STRING ": Set background color=%d\n", CONFIG_EXAMPLES_NX_BGCOLOR); + color = CONFIG_EXAMPLES_NX_BGCOLOR; + ret = nx_setbgcolor(g_hnx, &color); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_setbgcolor failed: %d\n", errno); + g_exitcode = NXEXIT_NXSETBGCOLOR; + goto errout_with_nx; + } + + /* Create window #1 */ + + message(MAIN_NAME_STRING ": Create window #1\n"); + nxeg_initstate(&g_wstate[0], 1, CONFIG_EXAMPLES_NX_COLOR1); + hwnd1 = nxeg_openwindow(&g_nxcb, &g_wstate[0]); + message(MAIN_NAME_STRING ": hwnd1=%p\n", hwnd1); + if (!hwnd1) + { + goto errout_with_nx; + } + + /* Wait until we have the screen resolution */ + + while (!b_haveresolution) + { + (void)sem_wait(&g_semevent); + } + message(MAIN_NAME_STRING ": Screen resolution (%d,%d)\n", g_xres, g_yres); + + /* Set the size of the window 1 */ + + size.w = g_xres / 2; + size.h = g_yres / 2; + + message(MAIN_NAME_STRING ": Set window #1 size to (%d,%d)\n", size.w, size.h); + ret = nxeg_setsize(hwnd1, &size); + if (ret < 0) + { + goto errout_with_hwnd1; + } + + /* Sleep a bit -- both so that we can see the result of the above operations + * but also, in the multi-user case, so that the server can get a chance to + * actually do them! + */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); + + /* Set the position of window #1 */ + + pt.x = g_xres / 8; + pt.y = g_yres / 8; + + message(MAIN_NAME_STRING ": Set window #1 postion to (%d,%d)\n", pt.x, pt.y); + ret = nxeg_setposition(hwnd1, &pt); + if (ret < 0) + { + goto errout_with_hwnd1; + } + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); + + /* Open the toolbar */ + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS + message(MAIN_NAME_STRING ": Add toolbar to window #1\n"); + ret = nxeq_opentoolbar(hwnd1, CONFIG_EXAMPLES_NX_TOOLBAR_HEIGHT, &g_tbcb, &g_wstate[0]); + if (ret < 0) + { + goto errout_with_hwnd1; + } + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); +#endif + + /* Create window #2 */ + + message(MAIN_NAME_STRING ": Create window #2\n"); + nxeg_initstate(&g_wstate[1], 2, CONFIG_EXAMPLES_NX_COLOR2); + hwnd2 = nxeg_openwindow(&g_nxcb, &g_wstate[1]); + message(MAIN_NAME_STRING ": hwnd2=%p\n", hwnd2); + if (!hwnd2) + { + goto errout_with_hwnd1; + } + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); + + /* Set the size of the window 2 == size of window 1*/ + + message(MAIN_NAME_STRING ": Set hwnd2 size to (%d,%d)\n", size.w, size.h); + ret = nxeg_setsize(hwnd2, &size); + if (ret < 0) + { + goto errout_with_hwnd2; + } + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); + + /* Set the position of window #2 */ + + pt.x = g_xres - size.w - pt.x; + pt.y = g_yres - size.h - pt.y; + + message(MAIN_NAME_STRING ": Set hwnd2 postion to (%d,%d)\n", pt.x, pt.y); + ret = nxeg_setposition(hwnd2, &pt); + if (ret < 0) + { + goto errout_with_hwnd2; + } + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); + +#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS + message(MAIN_NAME_STRING ": Add toolbar to window #2\n"); + ret = nxeq_opentoolbar(hwnd2, CONFIG_EXAMPLES_NX_TOOLBAR_HEIGHT, &g_tbcb, &g_wstate[1]); + if (ret < 0) + { + goto errout_with_hwnd2; + } + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); +#endif + + /* Give keyboard input to the top window -- should be window #2 */ + +#ifdef CONFIG_NX_KBD + message(MAIN_NAME_STRING ": Send keyboard input: %s\n", g_kbdmsg1); + ret = nx_kbdin(g_hnx, strlen((FAR const char *)g_kbdmsg1), g_kbdmsg1); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_kbdin failed: %d\n", errno); + goto errout_with_hwnd2; + } + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); +#endif + + /* Lower window 2 */ + + message(MAIN_NAME_STRING ": Lower window #2\n"); + ret = nxeg_lower(hwnd2); + if (ret < 0) + { + goto errout_with_hwnd2; + } + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); + + /* Put mouse left-button clicks all over the screen and see who responds */ + +#ifdef CONFIG_NX_MOUSE + nxeg_drivemouse(); + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); +#endif + + /* Give keyboard input to the top window -- should be window #1 */ + +#ifdef CONFIG_NX_KBD + message(MAIN_NAME_STRING ": Send keyboard input: %s\n", g_kbdmsg2); + ret = nx_kbdin(g_hnx, strlen((FAR const char *)g_kbdmsg2), g_kbdmsg2); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_kbdin failed: %d\n", errno); + goto errout_with_hwnd2; + } + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(1); +#endif + + /* Raise window 2 */ + + message(MAIN_NAME_STRING ": Raise window #2\n"); + ret = nxeg_raise(hwnd2); + if (ret < 0) + { + goto errout_with_hwnd2; + } + + /* Put mouse left-button clicks all over the screen and see who responds */ + +#ifdef CONFIG_NX_MOUSE + nxeg_drivemouse(); +#endif + + /* Sleep a bit */ + + message(MAIN_NAME_STRING ": Sleeping\n\n"); + sleep(2); + + /* Close the window 2 */ + +errout_with_hwnd2: + message(MAIN_NAME_STRING ": Close window #2\n"); + (void)nxeg_closewindow(hwnd2, &g_wstate[1]); + + /* Close the window1 */ + +errout_with_hwnd1: + message(MAIN_NAME_STRING ": Close window #1\n"); + (void)nxeg_closewindow(hwnd1, &g_wstate[0]); + +errout_with_nx: +#ifdef CONFIG_NX_MULTIUSER + /* Disconnect from the server */ + + message(MAIN_NAME_STRING ": Disconnect from the server\n"); + nx_disconnect(g_hnx); +#else + /* Close the server */ + + message(MAIN_NAME_STRING ": Close NX\n"); + nx_close(g_hnx); +#endif +errout: + return g_exitcode; +} diff --git a/apps/examples/nx/nx_server.c b/apps/examples/nx/nx_server.c new file mode 100644 index 000000000..a7a305d63 --- /dev/null +++ b/apps/examples/nx/nx_server.c @@ -0,0 +1,152 @@ +/**************************************************************************** + * examples/nx/nx_server.c + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sched.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/nx/nx.h> + +#ifdef CONFIG_NX_LCDDRIVER +# include <nuttx/lcd/lcd.h> +#else +# include <nuttx/fb.h> +#endif + +#include "nx_internal.h" + +#ifdef CONFIG_NX_MULTIUSER + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nx_servertask + ****************************************************************************/ + +int nx_servertask(int argc, char *argv[]) +{ + FAR NX_DRIVERTYPE *dev; + int ret; + +#if defined(CONFIG_EXAMPLES_NX_EXTERNINIT) + /* Use external graphics driver initialization */ + + message("nxeg_initialize: Initializing external graphics device\n"); + dev = up_nxdrvinit(CONFIG_EXAMPLES_NX_DEVNO); + if (!dev) + { + message("nxeg_initialize: up_nxdrvinit failed, devno=%d\n", CONFIG_EXAMPLES_NX_DEVNO); + g_exitcode = NXEXIT_EXTINITIALIZE; + return ERROR; + } + +#elif defined(CONFIG_NX_LCDDRIVER) + /* Initialize the LCD device */ + + message("nx_servertask: Initializing LCD\n"); + ret = up_lcdinitialize(); + if (ret < 0) + { + message("nx_servertask: up_lcdinitialize failed: %d\n", -ret); + return 1; + } + + /* Get the device instance */ + + dev = up_lcdgetdev(CONFIG_EXAMPLES_NX_DEVNO); + if (!dev) + { + message("nx_servertask: up_lcdgetdev failed, devno=%d\n", CONFIG_EXAMPLES_NX_DEVNO); + return 2; + } + + /* Turn the LCD on at 75% power */ + + (void)dev->setpower(dev, ((3*CONFIG_LCD_MAXPOWER + 3)/4)); +#else + /* Initialize the frame buffer device */ + + message("nx_servertask: Initializing framebuffer\n"); + ret = up_fbinitialize(); + if (ret < 0) + { + message("nx_servertask: up_fbinitialize failed: %d\n", -ret); + return 1; + } + + dev = up_fbgetvplane(CONFIG_EXAMPLES_NX_VPLANE); + if (!dev) + { + message("nx_servertask: up_fbgetvplane failed, vplane=%d\n", CONFIG_EXAMPLES_NX_VPLANE); + return 2; + } +#endif + + /* Then start the server */ + + ret = nx_run(dev); + message("nx_servertask: nx_run returned: %d\n", errno); + return 3; +} + +#endif /* CONFIG_NX_MULTIUSER */ diff --git a/apps/examples/nxffs/Makefile b/apps/examples/nxffs/Makefile new file mode 100644 index 000000000..1021bfc6d --- /dev/null +++ b/apps/examples/nxffs/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/examples/nxffs/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Hello, World! Example + +ASRCS = +CSRCS = nxffs_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/nxffs/nxffs_main.c b/apps/examples/nxffs/nxffs_main.c new file mode 100644 index 000000000..863f8bb43 --- /dev/null +++ b/apps/examples/nxffs/nxffs_main.c @@ -0,0 +1,947 @@ +/**************************************************************************** + * examples/nxffs/nxffs_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/mount.h> + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <string.h> +#include <errno.h> +#include <crc32.h> +#include <debug.h> + +#include <nuttx/mtd.h> +#include <nuttx/nxffs.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* The default is to use the RAM MTD device at drivers/mtd/rammtd.c. But + * an architecture-specific MTD driver can be used instead by defining + * CONFIG_EXAMPLES_NXFFS_ARCHINIT. In this case, the initialization logic + * will call nxffs_archinitialize() to obtain the MTD driver instance. + */ + +#ifndef CONFIG_EXAMPLES_NXFFS_ARCHINIT + +/* This must exactly match the default configuration in drivers/mtd/rammtd.c */ + +# ifndef CONFIG_RAMMTD_BLOCKSIZE +# define CONFIG_RAMMTD_BLOCKSIZE 512 +# endif + +# ifndef CONFIG_RAMMTD_ERASESIZE +# define CONFIG_RAMMTD_ERASESIZE 4096 +# endif + +# ifndef CONFIG_EXAMPLES_NXFFS_NEBLOCKS +# define CONFIG_EXAMPLES_NXFFS_NEBLOCKS (32) +# endif + +# undef CONFIG_EXAMPLES_NXFFS_BUFSIZE +# define CONFIG_EXAMPLES_NXFFS_BUFSIZE \ + (CONFIG_RAMMTD_ERASESIZE * CONFIG_EXAMPLES_NXFFS_NEBLOCKS) +#endif + +#ifndef CONFIG_EXAMPLES_NXFFS_MAXNAME +# define CONFIG_EXAMPLES_NXFFS_MAXNAME 128 +#endif + +#if CONFIG_EXAMPLES_NXFFS_MAXNAME > 255 +# undef CONFIG_EXAMPLES_NXFFS_MAXNAME +# define CONFIG_EXAMPLES_NXFFS_MAXNAME 255 +#endif + +#ifndef CONFIG_EXAMPLES_NXFFS_MAXFILE +# define CONFIG_EXAMPLES_NXFFS_MAXFILE 8192 +#endif + +#ifndef CONFIG_EXAMPLES_NXFFS_MAXIO +# define CONFIG_EXAMPLES_NXFFS_MAXIO 347 +#endif + +#ifndef CONFIG_EXAMPLES_NXFFS_MAXOPEN +# define CONFIG_EXAMPLES_NXFFS_MAXOPEN 512 +#endif + +#ifndef CONFIG_EXAMPLES_NXFFS_MOUNTPT +# define CONFIG_EXAMPLES_NXFFS_MOUNTPT "/mnt/nxffs" +#endif + +#ifndef CONFIG_EXAMPLES_NXFFS_NLOOPS +# define CONFIG_EXAMPLES_NXFFS_NLOOPS 100 +#endif + +#ifndef CONFIG_EXAMPLES_NXFFS_VERBOSE +# define CONFIG_EXAMPLES_NXFFS_VERBOSE 0 +#endif + +#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_FS) +# define message lib_rawprintf +# define msgflush() +#else +# define message printf +# define msgflush() fflush(stdout); +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nxffs_filedesc_s +{ + FAR char *name; + bool deleted; + size_t len; + uint32_t crc; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ +/* Pre-allocated simulated flash */ + +#ifndef CONFIG_EXAMPLES_NXFFS_ARCHINIT +static uint8_t g_simflash[CONFIG_EXAMPLES_NXFFS_BUFSIZE]; +#endif + +static uint8_t g_fileimage[CONFIG_EXAMPLES_NXFFS_MAXFILE]; +static struct nxffs_filedesc_s g_files[CONFIG_EXAMPLES_NXFFS_MAXOPEN]; +static const char g_mountdir[] = CONFIG_EXAMPLES_NXFFS_MOUNTPT "/"; +static int g_nfiles; +static int g_ndeleted; + +static struct mallinfo g_mmbefore; +static struct mallinfo g_mmprevious; +static struct mallinfo g_mmafter; + +/**************************************************************************** + * External Functions + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXFFS_ARCHINIT +extern FAR struct mtd_dev_s *nxffs_archinitialize(void); +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxffs_memusage + ****************************************************************************/ + +static void nxffs_showmemusage(struct mallinfo *mmbefore, + struct mallinfo *mmafter) +{ + message("VARIABLE BEFORE AFTER\n"); + message("======== ======== ========\n"); + message("arena %8x %8x\n", mmbefore->arena, mmafter->arena); + message("ordblks %8d %8d\n", mmbefore->ordblks, mmafter->ordblks); + message("mxordblk %8x %8x\n", mmbefore->mxordblk, mmafter->mxordblk); + message("uordblks %8x %8x\n", mmbefore->uordblks, mmafter->uordblks); + message("fordblks %8x %8x\n", mmbefore->fordblks, mmafter->fordblks); +} + +/**************************************************************************** + * Name: nxffs_loopmemusage + ****************************************************************************/ + +static void nxffs_loopmemusage(void) +{ + /* Get the current memory usage */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmafter = mallinfo(); +#else + (void)mallinfo(&g_mmafter); +#endif + + /* Show the change from the previous loop */ + + message("\nEnd of loop memory usage:\n"); + nxffs_showmemusage(&g_mmprevious, &g_mmafter); + + /* Set up for the next test */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmprevious = g_mmafter; +#else + memcpy(&g_mmprevious, &g_mmafter, sizeof(struct mallinfo)); +#endif +} + +/**************************************************************************** + * Name: nxffs_endmemusage + ****************************************************************************/ + +static void nxffs_endmemusage(void) +{ +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmafter = mallinfo(); +#else + (void)mallinfo(&g_mmafter); +#endif + message("\nFinal memory usage:\n"); + nxffs_showmemusage(&g_mmbefore, &g_mmafter); +} + +/**************************************************************************** + * Name: nxffs_randchar + ****************************************************************************/ + +static inline char nxffs_randchar(void) +{ + int value = rand() % 63; + if (value == 0) + { + return '/'; + } + else if (value <= 10) + { + return value + '0' - 1; + } + else if (value <= 36) + { + return value + 'a' - 11; + } + else /* if (value <= 62) */ + { + return value + 'A' - 37; + } +} + +/**************************************************************************** + * Name: nxffs_randname + ****************************************************************************/ + +static inline void nxffs_randname(FAR struct nxffs_filedesc_s *file) +{ + int dirlen; + int maxname; + int namelen; + int alloclen; + int i; + + dirlen = strlen(g_mountdir); + maxname = CONFIG_EXAMPLES_NXFFS_MAXNAME - dirlen; + namelen = (rand() % maxname) + 1; + alloclen = namelen + dirlen; + + file->name = (FAR char*)malloc(alloclen + 1); + if (!file->name) + { + message("ERROR: Failed to allocate name, length=%d\n", namelen); + msgflush(); + exit(5); + } + + memcpy(file->name, g_mountdir, dirlen); + for (i = dirlen; i < alloclen; i++) + { + file->name[i] = nxffs_randchar(); + } + + file->name[alloclen] = '\0'; +} + +/**************************************************************************** + * Name: nxffs_randfile + ****************************************************************************/ + +static inline void nxffs_randfile(FAR struct nxffs_filedesc_s *file) +{ + int i; + + file->len = (rand() % CONFIG_EXAMPLES_NXFFS_MAXFILE) + 1; + for (i = 0; i < file->len; i++) + { + g_fileimage[i] = nxffs_randchar(); + } + file->crc = crc32(g_fileimage, file->len); +} + +/**************************************************************************** + * Name: nxffs_freefile + ****************************************************************************/ + +static void nxffs_freefile(FAR struct nxffs_filedesc_s *file) +{ + if (file->name) + { + free(file->name); + } + memset(file, 0, sizeof(struct nxffs_filedesc_s)); +} + +/**************************************************************************** + * Name: nxffs_wrfile + ****************************************************************************/ + +static inline int nxffs_wrfile(FAR struct nxffs_filedesc_s *file) +{ + size_t offset; + int fd; + int ret; + + /* Create a random file */ + + nxffs_randname(file); + nxffs_randfile(file); + fd = open(file->name, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (fd < 0) + { + /* If it failed because there is no space on the device, then don't + * complain. + */ + + if (errno != ENOSPC) + { + message("ERROR: Failed to open file for writing: %d\n", errno); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + } + nxffs_freefile(file); + return ERROR; + } + + /* Write a random amount of data to the file */ + + for (offset = 0; offset < file->len; ) + { + size_t maxio = (rand() % CONFIG_EXAMPLES_NXFFS_MAXIO) + 1; + size_t nbytestowrite = file->len - offset; + ssize_t nbyteswritten; + + if (nbytestowrite > maxio) + { + nbytestowrite = maxio; + } + + nbyteswritten = write(fd, &g_fileimage[offset], nbytestowrite); + if (nbyteswritten < 0) + { + int err = errno; + + /* If the write failed because there is no space on the device, + * then don't complain. + */ + + if (err != ENOSPC) + { + message("ERROR: Failed to write file: %d\n", err); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + message(" Write offset: %d\n", offset); + message(" Write size: %d\n", nbytestowrite); + ret = ERROR; + } + close(fd); + + /* Remove any garbage file that might have been left behind */ + + ret = unlink(file->name); + if (ret < 0) + { + message(" Failed to remove partial file\n"); + } + else + { +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message(" Successfully removed partial file\n"); +#endif + } + + nxffs_freefile(file); + return ERROR; + } + else if (nbyteswritten != nbytestowrite) + { + message("ERROR: Partial write:\n"); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + message(" Write offset: %d\n", offset); + message(" Write size: %d\n", nbytestowrite); + message(" Written: %d\n", nbyteswritten); + } + offset += nbyteswritten; + } + + close(fd); + return OK; +} + +/**************************************************************************** + * Name: nxffs_fillfs + ****************************************************************************/ + +static int nxffs_fillfs(void) +{ + FAR struct nxffs_filedesc_s *file; + int ret; + int i; + + /* Create a file for each unused file structure */ + + for (i = 0; i < CONFIG_EXAMPLES_NXFFS_MAXOPEN; i++) + { + file = &g_files[i]; + if (file->name == NULL) + { + ret = nxffs_wrfile(file); + if (ret < 0) + { +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message("ERROR: Failed to write file %d\n", i); +#endif + return ERROR; + } + +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message(" Created file %s\n", file->name); +#endif + g_nfiles++; + } + } + + return OK; +} + +/**************************************************************************** + * Name: nxffs_rdblock + ****************************************************************************/ + +static ssize_t nxffs_rdblock(int fd, FAR struct nxffs_filedesc_s *file, + size_t offset, size_t len) +{ + size_t maxio = (rand() % CONFIG_EXAMPLES_NXFFS_MAXIO) + 1; + ssize_t nbytesread; + + if (len > maxio) + { + len = maxio; + } + + nbytesread = read(fd, &g_fileimage[offset], len); + if (nbytesread < 0) + { + message("ERROR: Failed to read file: %d\n", errno); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + message(" Read offset: %d\n", offset); + message(" Read size: %d\n", len); + return ERROR; + } + else if (nbytesread == 0) + { +#if 0 /* No... we do this on purpose sometimes */ + message("ERROR: Unexpected end-of-file:\n"); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + message(" Read offset: %d\n", offset); + message(" Read size: %d\n", len); +#endif + return ERROR; + } + else if (nbytesread != len) + { + message("ERROR: Partial read:\n"); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + message(" Read offset: %d\n", offset); + message(" Read size: %d\n", len); + message(" Bytes read: %d\n", nbytesread); + } + return nbytesread; +} + +/**************************************************************************** + * Name: nxffs_rdfile + ****************************************************************************/ + +static inline int nxffs_rdfile(FAR struct nxffs_filedesc_s *file) +{ + size_t ntotalread; + ssize_t nbytesread; + uint32_t crc; + int fd; + + /* Open the file for reading */ + + fd = open(file->name, O_RDONLY); + if (fd < 0) + { + if (!file->deleted) + { + message("ERROR: Failed to open file for reading: %d\n", errno); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + } + return ERROR; + } + + /* Read all of the data info the fileimage buffer using random read sizes */ + + for (ntotalread = 0; ntotalread < file->len; ) + { + nbytesread = nxffs_rdblock(fd, file, ntotalread, file->len - ntotalread); + if (nbytesread < 0) + { + close(fd); + return ERROR; + } + + ntotalread += nbytesread; + } + + /* Verify the file image CRC */ + + crc = crc32(g_fileimage, file->len); + if (crc != file->crc) + { + message("ERROR: Bad CRC: %d vs %d\n", crc, file->crc); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + close(fd); + return ERROR; + } + + /* Try reading past the end of the file */ + + nbytesread = nxffs_rdblock(fd, file, ntotalread, 1024) ; + if (nbytesread > 0) + { + message("ERROR: Read past the end of file\n"); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + message(" Bytes read: %d\n", nbytesread); + close(fd); + return ERROR; + } + + close(fd); + return OK; +} + +/**************************************************************************** + * Name: nxffs_verifyfs + ****************************************************************************/ + +static int nxffs_verifyfs(void) +{ + FAR struct nxffs_filedesc_s *file; + int ret; + int i; + + /* Create a file for each unused file structure */ + + for (i = 0; i < CONFIG_EXAMPLES_NXFFS_MAXOPEN; i++) + { + file = &g_files[i]; + if (file->name != NULL) + { + ret = nxffs_rdfile(file); + if (ret < 0) + { + if (file->deleted) + { +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message("Deleted file %d OK\n", i); +#endif + nxffs_freefile(file); + g_ndeleted--; + g_nfiles--; + } + else + { + message("ERROR: Failed to read a file: %d\n", i); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + return ERROR; + } + } + else + { + if (file->deleted) + { +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message("Succesffully read a deleted file\n"); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); +#endif + nxffs_freefile(file); + g_ndeleted--; + g_nfiles--; + return ERROR; + } + else + { +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message(" Verifed file %s\n", file->name); +#endif + } + } + } + } + + return OK; +} + +/**************************************************************************** + * Name: nxffs_delfiles + ****************************************************************************/ + +static int nxffs_delfiles(void) +{ + FAR struct nxffs_filedesc_s *file; + int ndel; + int ret; + int i; + int j; + + /* Are there any files to be deleted? */ + + int nfiles = g_nfiles - g_ndeleted; + if (nfiles < 1) + { + return 0; + } + + /* Yes... How many files should we delete? */ + + ndel = (rand() % nfiles) + 1; + + /* Now pick which files to delete */ + + for (i = 0; i < ndel; i++) + { + /* Guess a file index */ + + int ndx = (rand() % (g_nfiles - g_ndeleted)); + + /* And delete the next undeleted file after that random index */ + + for (j = ndx + 1; j != ndx;) + { + file = &g_files[j]; + if (file->name && !file->deleted) + { + ret = unlink(file->name); + if (ret < 0) + { + message("ERROR: Unlink %d failed: %d\n", i+1, errno); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + message(" File index: %d\n", j); + } + else + { +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message(" Deleted file %s\n", file->name); +#endif + file->deleted = true; + g_ndeleted++; + break; + } + } + + /* Increment the index and test for wrap-around */ + + if (++j >= CONFIG_EXAMPLES_NXFFS_MAXOPEN) + { + j = 0; + } + + } + } + + return OK; +} + +/**************************************************************************** + * Name: nxffs_delallfiles + ****************************************************************************/ + +static int nxffs_delallfiles(void) +{ + FAR struct nxffs_filedesc_s *file; + int ret; + int i; + + for (i = 0; i < CONFIG_EXAMPLES_NXFFS_MAXOPEN; i++) + { + file = &g_files[i]; + if (file->name) + { + ret = unlink(file->name); + if (ret < 0) + { + message("ERROR: Unlink %d failed: %d\n", i+1, errno); + message(" File name: %s\n", file->name); + message(" File size: %d\n", file->len); + message(" File index: %d\n", i); + } + else + { +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message(" Deleted file %s\n", file->name); +#endif + nxffs_freefile(file); + } + } + } + + g_nfiles = 0; + g_ndeleted = 0; + return OK; +} + +/**************************************************************************** + * Name: nxffs_directory + ****************************************************************************/ + +static int nxffs_directory(void) +{ + DIR *dirp; + FAR struct dirent *entryp; + int number; + + /* Open the directory */ + + dirp = opendir(CONFIG_EXAMPLES_NXFFS_MOUNTPT); + + if (!dirp) + { + /* Failed to open the directory */ + + message("ERROR: Failed to open directory '%s': %d\n", + CONFIG_EXAMPLES_NXFFS_MOUNTPT, errno); + return ERROR; + } + + /* Read each directory entry */ + + message("Directory:\n"); + number = 1; + do + { + entryp = readdir(dirp); + if (entryp) + { + message("%2d. Type[%d]: %s Name: %s\n", + number, entryp->d_type, + entryp->d_type == DTYPE_FILE ? "File " : "Error", + entryp->d_name); + } + number++; + } + while (entryp != NULL); + + closedir(dirp); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + FAR struct mtd_dev_s *mtd; + unsigned int i; + int ret; + + /* Seed the random number generated */ + + srand(0x93846); + + /* Create and initialize a RAM MTD device instance */ + +#ifdef CONFIG_EXAMPLES_NXFFS_ARCHINIT + mtd = nxffs_archinitialize(); +#else + mtd = rammtd_initialize(g_simflash, CONFIG_EXAMPLES_NXFFS_BUFSIZE); +#endif + if (!mtd) + { + message("ERROR: Failed to create RAM MTD instance\n"); + msgflush(); + exit(1); + } + + /* Initialize to provide NXFFS on an MTD interface */ + + ret = nxffs_initialize(mtd); + if (ret < 0) + { + message("ERROR: NXFFS initialization failed: %d\n", -ret); + msgflush(); + exit(2); + } + + /* Mount the file system */ + + ret = mount(NULL, CONFIG_EXAMPLES_NXFFS_MOUNTPT, "nxffs", 0, NULL); + if (ret < 0) + { + message("ERROR: Failed to mount the NXFFS volume: %d\n", errno); + msgflush(); + exit(3); + } + + /* Set up memory monitoring */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmbefore = mallinfo(); + g_mmprevious = g_mmbefore; +#else + (void)mallinfo(&g_mmbefore); + memcpy(&g_mmprevious, &g_mmbefore, sizeof(struct mallinfo)); +#endif + + /* Loop a few times ... file the file system with some random, files, + * delete some files randomly, fill the file system with more random file, + * delete, etc. This beats the FLASH very hard! + */ + +#if CONFIG_EXAMPLES_NXFFS_NLOOPS == 0 + for (i = 0; ; i++) +#else + for (i = 1; i <= CONFIG_EXAMPLES_NXFFS_NLOOPS; i++) +#endif + { + /* Write a files to the NXFFS file system until either (1) all of the + * open file structures are utilized or until (2) NXFFS reports an error + * (hopefully that the file system is full) + */ + + message("\n=== FILLING %d =============================\n", i); + ret = nxffs_fillfs(); + message("Filled file system\n"); + message(" Number of files: %d\n", g_nfiles); + message(" Number deleted: %d\n", g_ndeleted); + nxffs_dump(mtd, CONFIG_EXAMPLES_NXFFS_VERBOSE); + + /* Directory listing */ + + nxffs_directory(); + + /* Verify all files written to FLASH */ + + ret = nxffs_verifyfs(); + if (ret < 0) + { + message("ERROR: Failed to verify files\n"); + message(" Number of files: %d\n", g_nfiles); + message(" Number deleted: %d\n", g_ndeleted); + } + else + { +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message("Verified!\n"); + message(" Number of files: %d\n", g_nfiles); + message(" Number deleted: %d\n", g_ndeleted); +#endif + } + + /* Delete some files */ + + message("\n=== DELETING %d ============================\n", i); + ret = nxffs_delfiles(); + if (ret < 0) + { + message("ERROR: Failed to delete files\n"); + message(" Number of files: %d\n", g_nfiles); + message(" Number deleted: %d\n", g_ndeleted); + } + else + { + message("Deleted some files\n"); + message(" Number of files: %d\n", g_nfiles); + message(" Number deleted: %d\n", g_ndeleted); + } + nxffs_dump(mtd, CONFIG_EXAMPLES_NXFFS_VERBOSE); + + /* Directory listing */ + + nxffs_directory(); + + /* Verify all files written to FLASH */ + + ret = nxffs_verifyfs(); + if (ret < 0) + { + message("ERROR: Failed to verify files\n"); + message(" Number of files: %d\n", g_nfiles); + message(" Number deleted: %d\n", g_ndeleted); + } + else + { +#if CONFIG_EXAMPLES_NXFFS_VERBOSE != 0 + message("Verified!\n"); + message(" Number of files: %d\n", g_nfiles); + message(" Number deleted: %d\n", g_ndeleted); +#endif + } + + /* Show memory usage */ + + nxffs_loopmemusage(); + msgflush(); + } + + /* Delete all files then show memory usage again */ + + nxffs_delallfiles(); + nxffs_endmemusage(); + msgflush(); + return 0; +} + diff --git a/apps/examples/nxflat/Makefile b/apps/examples/nxflat/Makefile new file mode 100644 index 000000000..d2b99eb13 --- /dev/null +++ b/apps/examples/nxflat/Makefile @@ -0,0 +1,98 @@ +############################################################################ +# apps/examples/nxflat/Makefile +# +# Copyright (C) 2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NXFLAT Example + +ASRCS = +CSRCS = nxflat_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: headers clean depend disclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +headers: + @$(MAKE) -C tests TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +# We can't make dependencies in this directory because the required +# header files may not yet exist. + +.depend: + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/nxflat/nxflat_main.c b/apps/examples/nxflat/nxflat_main.c new file mode 100644 index 000000000..12d88c3d5 --- /dev/null +++ b/apps/examples/nxflat/nxflat_main.c @@ -0,0 +1,224 @@ +/**************************************************************************** + * examples/nxflat/nxflat_main.c + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/compiler.h> + +#include <sys/mount.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/ramdisk.h> +#include <nuttx/binfmt.h> +#include <nuttx/nxflat.h> + +#include "tests/romfs.h" +#include "tests/dirlist.h" +#include "tests/symtab.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Check configuration. This is not all of the configuration settings that + * are required -- only the more obvious. + */ + +#if CONFIG_NFILE_DESCRIPTORS < 1 +# error "You must provide file descriptors via CONFIG_NFILE_DESCRIPTORS in your configuration file" +#endif + +#ifndef CONFIG_NXFLAT +# error "You must select CONFIG_NXFLAT in your configuration file" +#endif + +#ifndef CONFIG_FS_ROMFS +# error "You must select CONFIG_FS_ROMFS in your configuration file" +#endif + +#ifdef CONFIG_DISABLE_MOUNTPOINT +# error "You must not disable mountpoints via CONFIG_DISABLE_MOUNTPOINT in your configuration file" +#endif + +#ifdef CONFIG_BINFMT_DISABLE +# error "You must not disable loadable modules via CONFIG_BINFMT_DISABLE in your configuration file" +#endif + +/* Describe the ROMFS file system */ + +#define SECTORSIZE 512 +#define NSECTORS(b) (((b)+SECTORSIZE-1)/SECTORSIZE) +#define ROMFSDEV "/dev/ram0" +#define MOUNTPT "/mnt/romfs" + +/* If CONFIG_DEBUG is enabled, use dbg instead of printf so that the + * output will be synchronous with the debug output. + */ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(format, arg...) dbg(format, ##arg) +# define err(format, arg...) dbg(format, ##arg) +# else +# define message(format, arg...) printf(format, ##arg) +# define err(format, arg...) fprintf(stderr, format, ##arg) +# endif +#else +# ifdef CONFIG_DEBUG +# define message dbg +# define err dbg +# else +# define message printf +# define err printf +# endif +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char delimiter[] = + "****************************************************************************"; + +static char path[128]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: testheader + ****************************************************************************/ + +static inline void testheader(FAR const char *progname) +{ + message("\n%s\n* Executing %s\n%s\n\n", delimiter, progname, delimiter); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + struct binary_s bin; + int ret; + int i; + + /* Initialize the NXFLAT binary loader */ + + message("Initializing the NXFLAT binary loader\n"); + ret = nxflat_initialize(); + if (ret < 0) + { + err("ERROR: Initialization of the NXFLAT loader failed: %d\n", ret); + exit(1); + } + + /* Create a ROM disk for the ROMFS filesystem */ + + message("Registering romdisk\n"); + ret = romdisk_register(0, romfs_img, NSECTORS(romfs_img_len), SECTORSIZE); + if (ret < 0) + { + err("ERROR: romdisk_register failed: %d\n", ret); + nxflat_uninitialize(); + exit(1); + } + + /* Mount the file system */ + + message("Mounting ROMFS filesystem at target=%s with source=%s\n", + MOUNTPT, ROMFSDEV); + + ret = mount(ROMFSDEV, MOUNTPT, "romfs", MS_RDONLY, NULL); + if (ret < 0) + { + err("ERROR: mount(%s,%s,romfs) failed: %s\n", + ROMFSDEV, MOUNTPT, errno); + nxflat_uninitialize(); + } + + /* Now excercise every progrm in the ROMFS file system */ + + for (i = 0; dirlist[i]; i++) + { + testheader(dirlist[i]); + + memset(&bin, 0, sizeof(struct binary_s)); + snprintf(path, 128, "%s/%s", MOUNTPT, dirlist[i]); + + bin.filename = path; + bin.exports = exports; + bin.nexports = NEXPORTS; + + ret = load_module(&bin); + if (ret < 0) + { + err("ERROR: Failed to load program '%s'\n", dirlist[i]); + exit(1); + } + + ret = exec_module(&bin, 50); + if (ret < 0) + { + err("ERROR: Failed to execute program '%s'\n", dirlist[i]); + unload_module(&bin); + } + + message("Wait a bit for test completion\n"); + sleep(4); + } + + message("End-of-Test.. Exit-ing\n"); + return 0; +} diff --git a/apps/examples/nxflat/tests/Makefile b/apps/examples/nxflat/tests/Makefile new file mode 100644 index 000000000..b5ecc041a --- /dev/null +++ b/apps/examples/nxflat/tests/Makefile @@ -0,0 +1,103 @@ +############################################################################ +# apps/examples/nxflat/tests/Makefile +# +# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# Most of these do no build yet +#SUBDIRS = errno hello hello++ longjmp mutex pthread signal task struct +SUBDIRS = errno hello mutex pthread task struct + +NXFLAT_DIR = $(APPDIR)/examples/nxflat +TESTS_DIR = $(NXFLAT_DIR)/tests +ROMFS_DIR = $(TESTS_DIR)/romfs +ROMFS_IMG = $(TESTS_DIR)/romfs.img +ROMFS_HDR = $(TESTS_DIR)/romfs.h +ROMFS_DIRLIST = $(TESTS_DIR)/dirlist.h +SYMTAB = $(TESTS_DIR)/symtab.h + +define DIR_template +$(1)_$(2): + @$(MAKE) -C $(1) $(3) TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" ROMFS_DIR="$(ROMFS_DIR)" CROSSDEV=$(CROSSDEV) +endef + +all: $(ROMFS_HDR) $(ROMFS_DIRLIST) $(SYMTAB) +.PHONY: all build clean install populate + +$(foreach DIR, $(SUBDIRS), $(eval $(call DIR_template,$(DIR),build, all))) +$(foreach DIR, $(SUBDIRS), $(eval $(call DIR_template,$(DIR),clean,clean))) +$(foreach DIR, $(SUBDIRS), $(eval $(call DIR_template,$(DIR),install,install))) + +# Build program(s) in each sud-directory + +build: $(foreach DIR, $(SUBDIRS), $(DIR)_build) + +# Install each program in the romfs directory + +install: $(foreach DIR, $(SUBDIRS), $(DIR)_install) + +# Create the romfs directory + +$(ROMFS_DIR): + @mkdir $(ROMFS_DIR) + +# Populate the romfs directory + +populate: $(ROMFS_DIR) build install + +# Create the romfs.img file from the populated romfs directory + +$(ROMFS_IMG): populate + @genromfs -f $@ -d $(ROMFS_DIR) -V "NXFLATTEST" + +# Create the romfs.h header file from the romfs.img file + +$(ROMFS_HDR) : $(ROMFS_IMG) + @(cd $(TESTS_DIR); xxd -i romfs.img | sed -e "s/^unsigned/static const unsigned/g" >$@) + +# Create the dirlist.h header file from the romfs directory + +$(ROMFS_DIRLIST) : populate + @$(TESTS_DIR)/mkdirlist.sh $(ROMFS_DIR) >$@ + +# Create the exported symbol table list from the derived *-thunk.S files + +$(SYMTAB): build + @$(TESTS_DIR)/mksymtab.sh $(TESTS_DIR) >$@ + +# Clean each subdirectory + +clean: $(foreach DIR, $(SUBDIRS), $(DIR)_clean) + @rm -f $(ROMFS_HDR) $(ROMFS_IMG) $(SYMTAB) + @rm -rf $(ROMFS_DIR) + + diff --git a/apps/examples/nxflat/tests/errno/Makefile b/apps/examples/nxflat/tests/errno/Makefile new file mode 100644 index 000000000..158768b85 --- /dev/null +++ b/apps/examples/nxflat/tests/errno/Makefile @@ -0,0 +1,78 @@ +############################################################################ +# examples/nxflat/tests/hello/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = errno + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -D $(BIN) $(ROMFS_DIR)/$(BIN) + diff --git a/apps/examples/nxflat/tests/errno/errno.c b/apps/examples/nxflat/tests/errno/errno.c new file mode 100644 index 000000000..b06679165 --- /dev/null +++ b/apps/examples/nxflat/tests/errno/errno.c @@ -0,0 +1,83 @@ +/**************************************************************************** + * examples/nxflat/tests/errno/errno.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +static const char g_nonexistent[] = "aflav-sautga-ay"; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + FILE *test_stream; + + /* Try using stdout and stderr explicitly. These are global variables + * exported from the base code. + */ + + fprintf(stdout, "Hello, World on stdout\n"); + fprintf(stderr, "Hello, World on stderr\n"); + + /* Try opening a non-existent file using buffered IO. */ + + test_stream = fopen(g_nonexistent, "r"); + if (test_stream) + { + fprintf(stderr, "Hmm... Delete \"%s\" and try this again\n", + g_nonexistent); + exit(1); + } + + /* Now print the errno on stderr. Errno is also a global + * variable exported by the base code. + */ + + fprintf(stderr, "We failed to open \"%s!\" errno is %d\n", + g_nonexistent, errno); + + return 0; +} diff --git a/apps/examples/nxflat/tests/hello++/Makefile b/apps/examples/nxflat/tests/hello++/Makefile new file mode 100644 index 000000000..113520da5 --- /dev/null +++ b/apps/examples/nxflat/tests/hello++/Makefile @@ -0,0 +1,180 @@ +############################################################################ +# examples/nxflat/tests/hello/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN1 = hello++1 +BIN2 = hello++2 +BIN3 = hello++3 +#BIN4 = hello++4 +ALL_BIN = $(BIN1) $(BIN2) $(BIN3) $(BIN4) + +R1SRCS1 = $(BIN1).c +R1OBJS1 = $(R1SRCS1:.c=.o) +R2SRC1 = $(BIN1)-thunk.S +R2OBJ1 = $(R2SRC1:.S=.o) + +R1SRCS2 = $(BIN2).c +R1OBJS2 = $(R1SRCS2:.c=.o) +R2SRC2 = $(BIN2)-thunk.S +R2OBJ2 = $(R2SRC2:.S=.o) + +R1SRCS3 = $(BIN3).c +R1OBJS3 = $(R1SRCS3:.c=.o) +R2SRC3 = $(BIN3)-thunk.S +R2OBJ3 = $(R2SRC3:.S=.o) + +#R1SRCS4 = $(BIN4).c +#R1OBJS4 = $(R1SRCS4:.c=.o) +#R2SRC4 = $(BIN4)-thunk.S +#R2OBJ4 = $(R2SRC4:.S=.o) + +DERIVED = $(R2SRC1) $(R2SRC2) $(R2SRC3) $(R2SRC4) + +R1CXXOBJS = $(R1OBJS1) $(R1OBJS2) $(R1OBJS3) # $(R1OBJS4) +R2AOBJS = $(R2OBJ1) $(R2OBJ2) $(R2OBJ3) # $(R2OBJ4) + +LIBSTDC_STUBS_DIR = $(TOPDIR)/libxx +LIBSTDC_STUBS_LIB = $(LIBSTDC_STUBS_DIR)/liblibxx.a + +all: $(BIN1) $(BIN2) $(BIN3) # $(BIN4) + +$(R1CXXOBJS): %.o: %.cpp + @echo "CC: $<" + @$(CXX) -c $(CXXPICFLAGS) $< -o $@ + +$(R2AOBJS): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +# This contains libstdc++ stubs to that you can build C++ code +# without actually having libstdc++ + +$(LIBSTDC_STUBS_LIB): + @$(MAKE) -C $(LIBSTDC_STUBS_DIR) TOPDIR=$(TOPDIR) + +# BIN1 and BIN2 link just like C code because they contain no +# static constructors. BIN1 is equivalent to a C hello world; +# BIN2 contains a class that implements hello world, but it is +# not statically initialized. + +$(BIN1).r1: $(R1OBJS1) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC1): $(BIN1).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN1).r2: $(R2OBJ1) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS1) $(R2OBJ1) + +$(BIN1): $(BIN1).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +$(BIN2).r1: $(R1OBJS2) $(LIBSTDC_STUBS_LIB) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC2): $(BIN2).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN2).r2: $(R2OBJ2) + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS2) $(R2OBJ2) + +$(BIN2): $(BIN2).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +# BIN3 and BIN4 require that we include --cxx in the xflat-ld command. +# This will instruct xflat-ld that we want it to put together the correct +# startup files to handle the C++ static initializers. +# +# BIN3 is equivalent to BIN2 except that is uses static initializers + +$(BIN3).r1: $(R1OBJS3) $(LIBSTDC_STUBS_LIB) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC3): $(BIN3).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN3).r2: $(R2OBJ3) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS3) $(R2OBJ3) + +$(BIN3): $(BIN3).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +# BIN4 is similar to BIN3 except that it uses the streams code from libstdc++ +# +# NOTE: libstdc++ is not available for XFLAT as of this writing +# +#$(BIN4).r1: $(R1OBJS4) $(LIBSTDC_STUBS_LIB) +# @echo "LD: $<" +# $(LD) $(NXFLATLDFLAGS1) -o $@ $^ +# +#$(R2SRC4): $(BIN4).r1 +# @echo "MK: $<" +# $(MKNXFLAT) -o $@ $^ +# +#$(BIN4).r2: $(R2OBJ4)# @echo "LD: $<" +# $(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS4) $(R2OBJ4) +# +#$(BIN4): $(BIN4).r2 +# @echo "LD: $<" +# $(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(ALL_BIN) $(DERIVED) *.o *.r1 *.r2 *~ .*.swp core + +install: $(ALL_BIN) + @install -D $(BIN1) $(ROMFS_DIR)/$(BIN1) + @install -D $(BIN2) $(ROMFS_DIR)/$(BIN2) + @install -D $(BIN3) $(ROMFS_DIR)/$(BIN3) +# @install -D $(BIN4) $(ROMFS_DIR)/$(BIN4) + + + + + + + diff --git a/apps/examples/nxflat/tests/hello++/hello++1.cpp b/apps/examples/nxflat/tests/hello++/hello++1.cpp new file mode 100644 index 000000000..779f3307a --- /dev/null +++ b/apps/examples/nxflat/tests/hello++/hello++1.cpp @@ -0,0 +1,60 @@ +///////////////////////////////////////////////////////////////////////////// +// examples/nxflat/tests/hello++/hello++1.c +// +// Copyright (C) 2009 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt <spudmonkey@racsa.co.cr> +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +///////////////////////////////////////////////////////////////////////////// +// +// This is an trivial version of "Hello, World" program. It illustrates +// that we can build C programs using the C++ compiler. +// +// - Building a C++ program to use the C library +// - No class creation +// - NO Streams +// - NO Static constructor and destructors +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// Included Files +///////////////////////////////////////////////////////////////////////////// + +#include <cstdio> + +///////////////////////////////////////////////////////////////////////////// +// Public Functions +///////////////////////////////////////////////////////////////////////////// + +int main(int argc, char **argv) +{ + printf("Hello, World!\n"); + return 0; +} diff --git a/apps/examples/nxflat/tests/hello++/hello++2.cpp b/apps/examples/nxflat/tests/hello++/hello++2.cpp new file mode 100644 index 000000000..87166f3ab --- /dev/null +++ b/apps/examples/nxflat/tests/hello++/hello++2.cpp @@ -0,0 +1,123 @@ +///////////////////////////////////////////////////////////////////////////// +// examples/nxflat/tests/hello++/hello++2.c +// +// Copyright (C) 2009 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt <spudmonkey@racsa.co.cr> +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +///////////////////////////////////////////////////////////////////////////// +// +// This is an another trivial version of "Hello, World" design. It illustrates +// +// - Building a C++ program to use the C library +// - Basic class creation +// - NO Streams +// - NO Static constructor and destructors +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// Included Files +///////////////////////////////////////////////////////////////////////////// + +#include <cstdio> + +///////////////////////////////////////////////////////////////////////////// +// Classes +///////////////////////////////////////////////////////////////////////////// + +class CThingSayer +{ + const char *szWhatToSay; +public: + CThingSayer(void) + { + printf("CThingSayer::CThingSayer: I am!\n"); + szWhatToSay = (const char*)NULL; + } + + ~CThingSayer(void) + { + printf("CThingSayer::~CThingSayer: I cease to be\n"); + if (szWhatToSay) + { + printf("CThingSayer::~CThingSayer: I will never say '%s' again\n", + szWhatToSay); + } + szWhatToSay = (const char*)NULL; + } + + void Initialize(const char *czSayThis) + { + printf("CThingSayer::Initialize: When told, I will say '%s'\n", + czSayThis); + szWhatToSay = czSayThis; + } + + void SayThing(void) + { + printf("CThingSayer::SayThing: I am now saying '%s'\n", szWhatToSay); + } +}; + +///////////////////////////////////////////////////////////////////////////// +// Public Functions +///////////////////////////////////////////////////////////////////////////// + +int main(int argc, char **argv) +{ + CThingSayer *MyThingSayer; + + printf("main: Started. Creating MyThingSayer\n"); + + // Create an instance of the CThingSayer class + // We should see the message from constructor, CThingSayer::CThingSayer(), + + MyThingSayer = new CThingSayer; + printf("main: Created MyThingSayer=0x%08lx\n", (long)MyThingSayer); + + // Tell MyThingSayer that "Hello, World!" is the string to be said + + printf("main: Calling MyThingSayer->Initialize\n");; + MyThingSayer->Initialize("Hello, World!"); + + // Tell MyThingSayer to say the thing we told it to say + + printf("main: Calling MyThingSayer->SayThing\n");; + MyThingSayer->SayThing(); + + // We should see the message from the destructor, + // CThingSayer::~CThingSayer(), AFTER we see the following + + printf("main: Destroying MyThingSayer\n"); + delete MyThingSayer; + + printf("main: Returning\n");; + return 0; +} diff --git a/apps/examples/nxflat/tests/hello++/hello++3.cpp b/apps/examples/nxflat/tests/hello++/hello++3.cpp new file mode 100644 index 000000000..ed7302fa6 --- /dev/null +++ b/apps/examples/nxflat/tests/hello++/hello++3.cpp @@ -0,0 +1,132 @@ +///////////////////////////////////////////////////////////////////////////// +// examples/nxflat/tests/hello++/hello++3.c +// +// Copyright (C) 2009 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt <spudmonkey@racsa.co.cr> +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +///////////////////////////////////////////////////////////////////////////// +// +// This is an another trivial version of "Hello, World" design. It illustrates +// +// - Building a C++ program to use the C library and stdio +// - Basic class creation with virtual methods. +// - Static constructor and destructors (in main program only) +// - NO Streams +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// Included Files +///////////////////////////////////////////////////////////////////////////// + +#include <cstdio> + +///////////////////////////////////////////////////////////////////////////// +// Classes +///////////////////////////////////////////////////////////////////////////// + +class CThingSayer +{ + const char *szWhatToSay; +public: + CThingSayer(void); + virtual ~CThingSayer(void); + virtual void Initialize(const char *czSayThis); + virtual void SayThing(void); +}; + +// A static instance of the CThingSayer class. This instance MUST +// be constructed by the system BEFORE the program is started at +// main() and must be destructed by the system AFTER the main() +// returns to the system + +static CThingSayer MyThingSayer; + +// These are implementations of the methods of the CThingSayer class + +CThingSayer::CThingSayer(void) +{ + printf("CThingSayer::CThingSayer: I am!\n"); + szWhatToSay = (const char*)NULL; +} + +CThingSayer::~CThingSayer(void) +{ + printf("CThingSayer::~CThingSayer: I cease to be\n"); + if (szWhatToSay) + { + printf("CThingSayer::~CThingSayer: I will never say '%s' again\n", + szWhatToSay); + } + szWhatToSay = (const char*)NULL; +} + +void CThingSayer::Initialize(const char *czSayThis) +{ + printf("CThingSayer::Initialize: When told, I will say '%s'\n", + czSayThis); + szWhatToSay = czSayThis; +} + +void CThingSayer::SayThing(void) +{ + printf("CThingSayer::SayThing: I am now saying '%s'\n", szWhatToSay); +} + +///////////////////////////////////////////////////////////////////////////// +// Public Functions +///////////////////////////////////////////////////////////////////////////// + +int main(int argc, char **argv) +{ + // We should see the message from constructor, CThingSayer::CThingSayer(), + // BEFORE we see the following messages. That is proof that the + // C++ static initializer is working + + printf("main: Started. MyThingSayer should already exist\n"); + + // Tell MyThingSayer that "Hello, World!" is the string to be said + + printf("main: Calling MyThingSayer.Initialize\n");; + MyThingSayer.Initialize("Hello, World!"); + + // Tell MyThingSayer to say the thing we told it to say + + printf("main: Calling MyThingSayer.SayThing\n");; + MyThingSayer.SayThing(); + + // We are finished, return. We should see the message from the + // destructor, CThingSayer::~CThingSayer(), AFTER we see the following + // message. That is proof that the C++ static destructor logic + // is working + + printf("main: Returning. MyThingSayer should be destroyed\n");; + return 0; +} diff --git a/apps/examples/nxflat/tests/hello++/hello++4.cpp b/apps/examples/nxflat/tests/hello++/hello++4.cpp new file mode 100644 index 000000000..97d026093 --- /dev/null +++ b/apps/examples/nxflat/tests/hello++/hello++4.cpp @@ -0,0 +1,150 @@ +///////////////////////////////////////////////////////////////////////////// +// examples/nxflat/tests/hello++/hello++4.c +// +// Copyright (C) 2009 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt <spudmonkey@racsa.co.cr> +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// 3. Neither the name NuttX nor the names of its contributors may be +// used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +///////////////////////////////////////////////////////////////////////////// +// +// This is an excessively complex version of "Hello, World" design to +// illustrate some basic properties of C++: +// +// - Building a C++ program +// - Streams / statically linked libstdc++ +// - Static constructor and destructors (in main program only) +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// Included Files +///////////////////////////////////////////////////////////////////////////// + +#include <cstdio> +#include <iostream> + +#ifndef NULL +# define NULL ((void*)0L) +#endif + +///////////////////////////////////////////////////////////////////////////// +// Classes +///////////////////////////////////////////////////////////////////////////// + +using namespace std; + +// A hello world sayer class + +class CThingSayer +{ + const char *szWhatToSay; +public: + CThingSayer(void); + virtual ~CThingSayer(void); + virtual void Initialize(const char *czSayThis); + virtual void SayThing(void); +}; + +///////////////////////////////////////////////////////////////////////////// +// Private Data +///////////////////////////////////////////////////////////////////////////// + +// A static instance of the CThingSayer class. This instance MUST +// be constructed by the system BEFORE the program is started at +// main() and must be destructed by the system AFTER the main() +// returns to the system + +static CThingSayer MyThingSayer; + +///////////////////////////////////////////////////////////////////////////// +// Method Implementations +///////////////////////////////////////////////////////////////////////////// + +// These are implementations of the methods of the CThingSayer class + +CThingSayer::CThingSayer(void) +{ + cout << "CThingSayer::CThingSayer: I am!" << endl; + szWhatToSay = (const char*)NULL; +} + +CThingSayer::~CThingSayer(void) +{ + cout << "CThingSayer::~CThingSayer: I cease to be" << endl; + if (szWhatToSay) + { + cout << "CThingSayer::~CThingSayer: I will never say '" + << szWhatToSay << "' again" << endl; + } + szWhatToSay = (const char*)NULL; +} + +void CThingSayer::Initialize(const char *czSayThis) +{ + cout << "CThingSayer::Initialize: When told, I will say '" + << czSayThis << "'" << endl; + szWhatToSay = czSayThis; +} + +void CThingSayer::SayThing(void) +{ + cout << "CThingSayer::SayThing: I am now saying '" + << szWhatToSay << "'" << endl; +} + +///////////////////////////////////////////////////////////////////////////// +// Public Functions +///////////////////////////////////////////////////////////////////////////// + +int main(int argc, char **argv) +{ + // We should see the message from constructor, CThingSayer::CThingSayer(), + // BEFORE we see the following messages. That is proof that the + // C++ static initializer is working + + cout << "main: Started" << endl; + + // Tell MyThingSayer that "Hello, World!" is the string to be said + + cout << "main: Calling MyThingSayer.Initialize" << endl; + MyThingSayer.Initialize("Hello, World!"); + + // Tell MyThingSayer to say the thing we told it to say + + cout << "main: Calling MyThingSayer.SayThing" << endl; + MyThingSayer.SayThing(); + + // We are finished, return. We should see the message from the + // destructor, CThingSayer::~CThingSayer(), AFTER we see the following + // message. That is proof that the C++ static destructor logic + // is working + + cout << "main: Returning" << endl; + return 0; +} diff --git a/apps/examples/nxflat/tests/hello/Makefile b/apps/examples/nxflat/tests/hello/Makefile new file mode 100644 index 000000000..ccde7a98f --- /dev/null +++ b/apps/examples/nxflat/tests/hello/Makefile @@ -0,0 +1,78 @@ +############################################################################ +# examples/nxflat/tests/hello/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = hello + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -D $(BIN) $(ROMFS_DIR)/$(BIN) + diff --git a/apps/examples/nxflat/tests/hello/hello.c b/apps/examples/nxflat/tests/hello/hello.c new file mode 100644 index 000000000..028bdfe00 --- /dev/null +++ b/apps/examples/nxflat/tests/hello/hello.c @@ -0,0 +1,78 @@ +/**************************************************************************** + * examples/nxflat/tests/hello/hello.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + int i; + + /* Mandatory "Hello, world!" */ + + puts("Getting ready to say \"Hello, world\"\n"); + printf("Hello, world!\n"); + puts("It has been said.\n"); + + /* Print arguments */ + + printf("argc\t= %d\n", argc); + printf("argv\t= 0x%p\n", argv); + + for (i = 0; i < argc; i++) + { + printf("argv[%d]\t= ", i); + if (argv[i]) + { + printf("(0x%p) \"%s\"\n", argv[i], argv[i]); + } + else + { + printf("NULL?\n"); + } + } + + printf("argv[%d]\t= 0x%p\n", argc, argv[argc]); + printf("Goodbye, world!\n"); + return 0; +} diff --git a/apps/examples/nxflat/tests/longjmp/Makefile b/apps/examples/nxflat/tests/longjmp/Makefile new file mode 100644 index 000000000..d0c93ebbd --- /dev/null +++ b/apps/examples/nxflat/tests/longjmp/Makefile @@ -0,0 +1,78 @@ +############################################################################ +# examples/nxflat/tests/longjmp/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = longjmp + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -D $(BIN) $(ROMFS_DIR)/$(BIN) + diff --git a/apps/examples/nxflat/tests/longjmp/longjmp.c b/apps/examples/nxflat/tests/longjmp/longjmp.c new file mode 100644 index 000000000..b5b317d99 --- /dev/null +++ b/apps/examples/nxflat/tests/longjmp/longjmp.c @@ -0,0 +1,128 @@ +/**************************************************************************** + * examples/nxflat/tests/longjmp/longjmp.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <setjmp.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MAIN_VAL 47 +#define FUNC_VAL 92 +#define LEAF_VAL 163 + +#define FUNCTION_ARG MAIN_VAL +#define LEAF_ARG (FUNCTION_ARG + FUNC_VAL) +#define SETJMP_RETURN (LEAF_ARG + LEAF_VAL) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static jmp_buf env; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int leaf(int *some_arg) +{ + int some_local_variable = *some_arg + LEAF_VAL; + + printf("leaf: received %d\n", *some_arg); + + if (*some_arg != LEAF_ARG) + printf("leaf: ERROR: expected %d\n", LEAF_ARG); + + printf("leaf: Calling longjmp() with %d\n", some_local_variable); + + longjmp(env, some_local_variable); +} + +static int function(int some_arg) +{ + int some_local_variable = some_arg + FUNC_VAL; + int retval; + + printf("function: received %d\n", some_arg); + + if (some_arg != FUNCTION_ARG) + printf("function: ERROR: expected %d\n", FUNCTION_ARG); + + printf("function: Calling leaf() with %d\n", some_local_variable); + + retval = leaf(&some_local_variable); + + printf("function: ERROR -- leaf returned!\n"); + return retval; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + int value; + + printf("main: Calling setjmp\n"); + value = setjmp(env); + printf("main: setjmp returned %d\n", value); + + if (value == 0) + { + printf("main: Normal setjmp return\n"); + printf("main: Calling function with %d\n", MAIN_VAL); + function(MAIN_VAL); + printf("main: ERROR -- function returned!\n"); + return 1; + } + else if (value != SETJMP_RETURN) + { + printf("main: ERROR: Expected %d\n", SETJMP_RETURN); + return 1; + } + else + { + printf("main: SUCCESS: setjmp return from longjmp call\n"); + return 0; + } +} + diff --git a/apps/examples/nxflat/tests/mkdirlist.sh b/apps/examples/nxflat/tests/mkdirlist.sh new file mode 100755 index 000000000..cc55ac0b5 --- /dev/null +++ b/apps/examples/nxflat/tests/mkdirlist.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +usage="Usage: %0 <romfs-dir-path>" + +dir=$1 +if [ -z "$dir" ]; then + echo "ERROR: Missing <romfs-dir-path>" + echo "" + echo $usage + exit 1 +fi + +if [ ! -d "$dir" ]; then + echo "ERROR: Directory $dir does not exist" + echo "" + echo $usage + exit 1 +fi + +echo "#ifndef __EXAMPLES_NXFLAT_TESTS_DIRLIST_H" +echo "#define __EXAMPLES_NXFLAT_TESTS_DIRLIST_H" +echo "" +echo "static const char *dirlist[] =" +echo "{" + +for file in `ls $dir`; do + echo " \"$file\"," +done + +echo " NULL" +echo "};" +echo "" +echo "#endif /* __EXAMPLES_NXFLAT_TESTS_DIRLIST_H */" + + diff --git a/apps/examples/nxflat/tests/mksymtab.sh b/apps/examples/nxflat/tests/mksymtab.sh new file mode 100755 index 000000000..611d3a87a --- /dev/null +++ b/apps/examples/nxflat/tests/mksymtab.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +usage="Usage: %0 <test-dir-path>" + +dir=$1 +if [ -z "$dir" ]; then + echo "ERROR: Missing <test-dir-path>" + echo "" + echo $usage + exit 1 +fi + +if [ ! -d "$dir" ]; then + echo "ERROR: Directory $dir does not exist" + echo "" + echo $usage + exit 1 +fi + +varlist=`find $dir -name "*-thunk.S"| xargs grep -h asciz | cut -f3 | sort | uniq` + +echo "#ifndef __EXAMPLES_NXFLAT_TESTS_SYMTAB_H" +echo "#define __EXAMPLES_NXFLAT_TESTS_SYMTAB_H" +echo "" +echo "#include <nuttx/symtab.h>" +echo "" +echo "static const struct symtab_s exports[] = " +echo "{" + +for string in $varlist; do + var=`echo $string | sed -e "s/\"//g"` + echo " {$string, $var}," +done + +echo "};" +echo "#define NEXPORTS (sizeof(exports)/sizeof(struct symtab_s))" +echo "" +echo "#endif /* __EXAMPLES_NXFLAT_TESTS_SYMTAB_H */" + diff --git a/apps/examples/nxflat/tests/mutex/Makefile b/apps/examples/nxflat/tests/mutex/Makefile new file mode 100644 index 000000000..8c9fbb4a3 --- /dev/null +++ b/apps/examples/nxflat/tests/mutex/Makefile @@ -0,0 +1,78 @@ +############################################################################ +# examples/nxflat/tests/mutex/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = mutex + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -D $(BIN) $(ROMFS_DIR)/$(BIN) + diff --git a/apps/examples/nxflat/tests/mutex/mutex.c b/apps/examples/nxflat/tests/mutex/mutex.c new file mode 100644 index 000000000..78a63306d --- /dev/null +++ b/apps/examples/nxflat/tests/mutex/mutex.c @@ -0,0 +1,149 @@ +/**************************************************************************** + * examples/nxflat/tests/mutex/mutex.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthread.h> + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static pthread_mutex_t mut; +static volatile int my_mutex = 0; +static unsigned long nloops[2] = {0, 0}; +static unsigned long nerrors[2] = {0, 0}; +static volatile bool bendoftest; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* NOTE: it is necessary for functions that are referred to by function pointers + * pointer to be declared with global scope (at least for ARM). Otherwise, + * a relocation type that is not supported by NXFLAT is generated by GCC. + */ + +void thread_func(void *parameter) +{ + int my_id = (int)parameter; + int my_ndx = my_id - 1; + int i; + + /* Loop 20 times. There is a 100 MS delay in the loop so this should + * take about 2 seconds. The main thread will stop this thread after + * 2 seconds by setting bendoftest in any event. + */ + + for (i = 0; i < 20 && !bendoftest; i++); + { + if ((pthread_mutex_lock(&mut)) != 0) + { + printf("ERROR thread %d: pthread_mutex_lock failed\n", my_id); + } + + if (my_mutex == 1) + { + printf("ERROR thread=%d: " + "my_mutex should be zero, instead my_mutex=%d\n", + my_id, my_mutex); + nerrors[my_ndx]++; + } + + my_mutex = 1; + usleep(100000); + my_mutex = 0; + + if ((pthread_mutex_unlock(&mut)) != 0) + { + printf("ERROR thread %d: pthread_mutex_unlock failed\n", my_id); + } + + nloops[my_ndx]++; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + pthread_t thread1; + pthread_t thread2; + + /* Initialize the mutex */ + + pthread_mutex_init(&mut, NULL); + + /* Start two thread instances */ + + printf("Starting thread 1\n"); + bendoftest = false; + if ((pthread_create(&thread1, NULL, (void*)thread_func, (void*)1)) != 0) + { + fprintf(stderr, "Error in thread#1 creation\n"); + } + + printf("Starting thread 2\n"); + if ((pthread_create(&thread2, NULL, (void*)thread_func, (void*)2)) != 0) + { + fprintf(stderr, "Error in thread#2 creation\n"); + } + + /* Wait a bit for the threads to do their thing. */ + + sleep(2); + + /* Then ask them politely to stop running */ + + printf("Stopping threads\n"); + bendoftest = true; + pthread_join(thread1, NULL); + pthread_join(thread2, NULL); + + printf("\tThread1\tThread2\n"); + printf("Loops\t%ld\t%ld\n", nloops[0], nloops[1]); + printf("Errors\t%ld\t%ld\n", nerrors[0], nerrors[1]); + + return 0; +} + diff --git a/apps/examples/nxflat/tests/pthread/Makefile b/apps/examples/nxflat/tests/pthread/Makefile new file mode 100644 index 000000000..27da42e7c --- /dev/null +++ b/apps/examples/nxflat/tests/pthread/Makefile @@ -0,0 +1,78 @@ +############################################################################ +# examples/nxflat/tests/pthread/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = pthread + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -D $(BIN) $(ROMFS_DIR)/$(BIN) + diff --git a/apps/examples/nxflat/tests/pthread/pthread.c b/apps/examples/nxflat/tests/pthread/pthread.c new file mode 100644 index 000000000..019ec453e --- /dev/null +++ b/apps/examples/nxflat/tests/pthread/pthread.c @@ -0,0 +1,143 @@ +/**************************************************************************** + * examples/nxflat/tests/pthread/pthread.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthread.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CHILD_ARG ((void*)0x12345678) +#define CHILD_RET ((void*)0x87654321) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum exit_values_e +{ + TESTRESULT_SUCCESS = 0, + TESTRESULT_PTHREAD_ATTR_INIT_FAIL, + TESTRESULT_PTHREAD_CREATE_FAIL, + TESTRESULT_PTHREAD_JOIN_FAIL, + TESTRESULT_CHILD_ARG_FAIL, + TESTRESULT_CHILD_RETVAL_FAIL, +}; + +/**************************************************************************** + * External Functions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* NOTE: it is necessary for functions that are referred to by function pointers + * pointer to be declared with global scope (at least for ARM). Otherwise, + * a relocation type that is not supported by NXFLAT is generated by GCC. + */ + +void *child_start_routine(void *arg) +{ + printf("CHILD: started with arg=%d\n", (int)arg); + + if (arg != CHILD_ARG) + { + printf("CHILD: expected arg=%d\n", (int)CHILD_ARG); + return (void*)TESTRESULT_CHILD_ARG_FAIL; + } + sleep(2); + + printf("CHILD: returning %d\n", (int)CHILD_RET); + pthread_exit(CHILD_RET); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + pthread_attr_t attr; + pthread_t thread; + void *retval; + int status; + + puts("PARENT: started\n"); + + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("PARENT: pthread_attr_init() returned %d\n", status); + exit(TESTRESULT_PTHREAD_ATTR_INIT_FAIL); + } + + printf("PARENT: calling pthread_start with arg=%d\n", (int)CHILD_ARG); + status = pthread_create(&thread, &attr, child_start_routine, CHILD_ARG); + if (status != 0) + { + printf("PARENT: pthread_create() returned %d\n", status); + exit(TESTRESULT_PTHREAD_CREATE_FAIL); + } + + status = pthread_join(thread, &retval); + if (status != 0) + { + printf("PARENT pthread_join() returned %d\n", status); + + exit(TESTRESULT_PTHREAD_JOIN_FAIL); + } + + printf("PARENT child exitted with %d\n", (int)retval); + if (retval != CHILD_RET) + { + printf("PARENT child thread did not exit with %d\n", (int)CHILD_RET); + exit(TESTRESULT_CHILD_RETVAL_FAIL); + } + + puts("PARENT returning success\n"); + return TESTRESULT_SUCCESS; +} diff --git a/apps/examples/nxflat/tests/signal/Makefile b/apps/examples/nxflat/tests/signal/Makefile new file mode 100644 index 000000000..d967fbf09 --- /dev/null +++ b/apps/examples/nxflat/tests/signal/Makefile @@ -0,0 +1,78 @@ +############################################################################ +# examples/nxflat/tests/signal/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = signal + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -D $(BIN) $(ROMFS_DIR)/$(BIN) + diff --git a/apps/examples/nxflat/tests/signal/signal.c b/apps/examples/nxflat/tests/signal/signal.c new file mode 100644 index 000000000..ff1c58305 --- /dev/null +++ b/apps/examples/nxflat/tests/signal/signal.c @@ -0,0 +1,308 @@ +/**************************************************************************** + * examples/nxflat/tests/signal/signal.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define USEC_PER_MSEC 1000 +#define MSEC_PER_SEC 1000 +#define USEC_PER_SEC (USEC_PER_MSEC * MSEC_PER_SEC) +#define SHORT_DELAY (USEC_PER_SEC / 3) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static int sigusr1_rcvd = 0; +static int sigusr2_rcvd = 0; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sigusr1_sighandler + ****************************************************************************/ + +/* NOTE: it is necessary for functions that are referred to by function pointers + * pointer to be declared with global scope (at least for ARM). Otherwise, + * a relocation type that is not supported by NXFLAT is generated by GCC. + */ + +void sigusr1_sighandler(int signo) +{ + printf("sigusr1_sighandler: Received SIGUSR1, signo=%d\n", signo); + sigusr1_rcvd = 1; +} + +/**************************************************************************** + * Name: sigusr2_sigaction + ***************************************************************************/ + +/* NOTE: it is necessary for functions that are referred to by function pointers + * pointer to be declared with global scope (at least for ARM). Otherwise, + * a relocation type that is not supported by NXFLAT is generated by GCC. + */ + +#ifdef __USE_POSIX199309 +void sigusr2_sigaction(int signo, siginfo_t *siginfo, void *arg) +{ + printf("sigusr2_sigaction: Received SIGUSR2, signo=%d siginfo=%p arg=%p\n", + signo, siginfo, arg); + +#ifdef HAVE_SIGQUEUE + if (siginfo) + { + printf(" si_signo = %d\n", siginfo->si_signo); + printf(" si_errno = %d\n", siginfo->si_errno); + printf(" si_code = %d\n", siginfo->si_code); + printf(" si_pid = %d\n", siginfo->si_pid); + printf(" si_uid = %d\n", siginfo->si_uid); + printf(" si_status = %d\n", siginfo->si_status); + printf(" si_utime = %ld\n", (long)siginfo->si_utime); + printf(" si_stime = %ld\n", (long)siginfo->si_stime); + printf(" si_value = %d\n", siginfo->si_value.sival_int); + printf(" si_int = %d\n", siginfo->si_int); + printf(" si_ptr = %p\n", siginfo->si_ptr); + printf(" si_addr = %p\n", siginfo->si_addr); + printf(" si_band = %ld\n", siginfo->si_band); + printf(" si_fd = %d\n", siginfo->si_fd); + } +#endif + sigusr2_rcvd = 1; +} +#else +void sigusr2_sigaction(int signo) +{ + printf("sigusr2_sigaction: Received SIGUSR2, signo=%d\n", signo); + sigusr2_rcvd = 1; +} + +#endif + +/**************************************************************************** + * Name: sigusr2_sighandler + ****************************************************************************/ + +static void sigusr2_sighandler(int signo) +{ + printf("sigusr2_sighandler: Received SIGUSR2, signo=%d\n", signo); + sigusr2_rcvd = 1; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: main + ****************************************************************************/ + +int main(int argc, char **argv) +{ + struct sigaction act; + struct sigaction oact; + void (*old_sigusr1_sighandler)(int signo); + void (*old_sigusr2_sighandler)(int signo); + pid_t mypid = getpid(); +#if defined(__USE_POSIX199309) && defined(HAVE_SIGQUEUE) + sigval_t sigval; +#endif + int status; + + printf("Setting up signal handlers from pid=%d\n", mypid); + + /* Set up so that sigusr1_sighandler will respond to SIGUSR1 */ + + old_sigusr1_sighandler = signal(SIGUSR1, sigusr1_sighandler); + if (old_sigusr1_sighandler == SIG_ERR) + { + fprintf(stderr, "Failed to install SIGUSR1 handler, errno=%d\n", + errno); + exit(1); + } + + printf("Old SIGUSR1 sighandler at %p\n", old_sigusr1_sighandler); + printf("New SIGUSR1 sighandler at %p\n", sigusr1_sighandler); + + /* Set up so that sigusr2_sigaction will respond to SIGUSR2 */ + + memset(&act, 0, sizeof(struct sigaction)); + act.sa_sigaction = sigusr2_sigaction; + act.sa_flags = SA_SIGINFO; + + (void)sigemptyset(&act.sa_mask); + + status = sigaction(SIGUSR2, &act, &oact); + if (status != 0) + { + fprintf(stderr, "Failed to install SIGUSR2 handler, errno=%d\n", + errno); + exit(2); + } + + printf("Old SIGUSR2 sighandler at %p\n", oact.sa_handler); + printf("New SIGUSR2 sighandler at %p\n", sigusr2_sigaction); + printf("Raising SIGUSR1 from pid=%d\n", mypid); + + fflush(stdout); usleep(SHORT_DELAY); + + /* Send SIGUSR1 to ourselves via raise() */ + + status = raise(SIGUSR1); + if (status != 0) + { + fprintf(stderr, "Failed to raise SIGUSR1, errno=%d\n", errno); + exit(3); + } + + usleep(SHORT_DELAY); + printf("SIGUSR1 raised from pid=%d\n", mypid); + + /* Verify that we received SIGUSR1 */ + + if (sigusr1_rcvd == 0) + { + fprintf(stderr, "SIGUSR1 not received\n"); + exit(4); + } + sigusr1_rcvd = 0; + + /* Send SIGUSR2 to ourselves */ + + printf("Killing SIGUSR2 from pid=%d\n", mypid); + fflush(stdout); usleep(SHORT_DELAY); + +#if defined(__USE_POSIX199309) && defined(HAVE_SIGQUEUE) + /* Send SIGUSR2 to ourselves via sigqueue() */ + + sigval.sival_int = 87; + status = sigqueue(mypid, SIGUSR2, sigval); + if (status != 0) + { + fprintf(stderr, "Failed to queue SIGUSR2, errno=%d\n", errno); + exit(5); + } + + usleep(SHORT_DELAY); + printf("SIGUSR2 queued from pid=%d, sigval=97\n", mypid); +#else + /* Send SIGUSR2 to ourselves via kill() */ + + status = kill(mypid, SIGUSR2); + if (status != 0) + { + fprintf(stderr, "Failed to kill SIGUSR2, errno=%d\n", errno); + exit(5); + } + + usleep(SHORT_DELAY); + printf("SIGUSR2 killed from pid=%d\n", mypid); +#endif + /* Verify that SIGUSR2 was received */ + + if (sigusr2_rcvd == 0) + { + fprintf(stderr, "SIGUSR2 not received\n"); + exit(6); + } + sigusr2_rcvd = 0; + + /* Remove the sigusr2_sigaction handler and replace the SIGUSR2 + * handler with sigusr2_sighandler. + */ + + printf("Resetting SIGUSR2 signal handler from pid=%d\n", mypid); + + old_sigusr2_sighandler = signal(SIGUSR2, sigusr2_sighandler); + if (old_sigusr2_sighandler == SIG_ERR) + { + fprintf(stderr, "Failed to install SIGUSR2 handler, errno=%d\n", + errno); + exit(7); + } + + printf("Old SIGUSR2 sighandler at %p\n", old_sigusr2_sighandler); + printf("New SIGUSR2 sighandler at %p\n", sigusr2_sighandler); + + /* Verify that the handler that was removed was sigusr2_sigaction */ + + if ((void*)old_sigusr2_sighandler != (void*)sigusr2_sigaction) + { + fprintf(stderr, + "Old SIGUSR2 signhanlder (%p) is not sigusr2_sigation (%p)\n", + old_sigusr2_sighandler, sigusr2_sigaction); + exit(8); + } + + /* Send SIGUSR2 to ourselves via kill() */ + + printf("Killing SIGUSR2 from pid=%d\n", mypid); + fflush(stdout); usleep(SHORT_DELAY); + + status = kill(mypid, SIGUSR2); + if (status != 0) + { + fprintf(stderr, "Failed to kill SIGUSR2, errno=%d\n", errno); + exit(9); + } + + usleep(SHORT_DELAY); + printf("SIGUSR2 killed from pid=%d\n", mypid); + + /* Verify that SIGUSR2 was received */ + + if (sigusr2_rcvd == 0) + { + fprintf(stderr, "SIGUSR2 not received\n"); + exit(10); + } + sigusr2_rcvd = 0; + + return 0; +} diff --git a/apps/examples/nxflat/tests/struct/Makefile b/apps/examples/nxflat/tests/struct/Makefile new file mode 100644 index 000000000..7a5f3fb82 --- /dev/null +++ b/apps/examples/nxflat/tests/struct/Makefile @@ -0,0 +1,80 @@ +############################################################################ +# examples/nxflat/tests/hello/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +CFLAGS += -I. + +BIN = struct + +R1SRCS = struct_main.c struct_dummy.c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -D $(BIN) $(ROMFS_DIR)/$(BIN) + diff --git a/apps/examples/nxflat/tests/struct/struct.h b/apps/examples/nxflat/tests/struct/struct.h new file mode 100644 index 000000000..0b1747d8c --- /dev/null +++ b/apps/examples/nxflat/tests/struct/struct.h @@ -0,0 +1,89 @@ +/**************************************************************************** + * examples/nxflat/tests/struct/struct.h + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_NXFLAT_TESTS_STRUCT_STRUCT_H +#define __EXAMPLES_NXFLAT_TESTS_STRUCT_STRUCT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DUMMY_SCALAR_VALUE1 42 +#define DUMMY_SCALAR_VALUE2 87 +#define DUMMY_SCALAR_VALUE3 117 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef void (*dummy_t)(void); + +struct struct_dummy_s +{ + int n; /* This is a simple scalar value (DUMMY_SCALAR_VALUE3) */ +}; + +struct struct_s +{ + int n; /* This is a simple scalar value (DUMMY_SCALAR_VALUE1) */ + const int *pn; /* This is a pointer to a simple scalar value */ + const struct struct_dummy_s *ps; /* This is a pointer to a structure */ + dummy_t pf; /* This is a pointer to a function */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern int dummy_scalar; /* (DUMMY_SCALAR_VALUE2) */ +extern const struct struct_dummy_s dummy_struct; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +extern void dummyfunc(void); +extern const struct struct_s *getstruct(void); + +#endif /* __EXAMPLES_NXFLAT_TESTS_STRUCT_STRUCT_H */ + + diff --git a/apps/examples/nxflat/tests/struct/struct_dummy.c b/apps/examples/nxflat/tests/struct/struct_dummy.c new file mode 100644 index 000000000..7f0be6a1f --- /dev/null +++ b/apps/examples/nxflat/tests/struct/struct_dummy.c @@ -0,0 +1,65 @@ +/**************************************************************************** + * examples/nxflat/tests/struct/struct_dummy.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +#include "struct.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct struct_s dummy = +{ + DUMMY_SCALAR_VALUE1, + &dummy_scalar, + &dummy_struct, + (dummy_t)dummyfunc +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +const struct struct_s *getstruct(void) +{ + return &dummy; +} + diff --git a/apps/examples/nxflat/tests/struct/struct_main.c b/apps/examples/nxflat/tests/struct/struct_main.c new file mode 100644 index 000000000..d82cdd706 --- /dev/null +++ b/apps/examples/nxflat/tests/struct/struct_main.c @@ -0,0 +1,109 @@ +/**************************************************************************** + * examples/nxflat/tests/struct/struct_main.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +#include "struct.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct struct_dummy_s dummy_struct = +{ + DUMMY_SCALAR_VALUE3 +}; + +int dummy_scalar = DUMMY_SCALAR_VALUE2; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + const struct struct_s *mystruct = getstruct(); + + printf("Calling getstruct()\n"); + mystruct = getstruct(); + printf("getstruct returned %p\n", mystruct); + printf(" n = %d (vs %d) %s\n", + mystruct->n, DUMMY_SCALAR_VALUE1, + mystruct->n == DUMMY_SCALAR_VALUE1 ? "PASS" : "FAIL"); + + printf(" pn = %p (vs %p) %s\n", + mystruct->pn, &dummy_scalar, + mystruct->pn == &dummy_scalar ? "PASS" : "FAIL"); + if (mystruct->pn == &dummy_scalar) + { + printf(" *pn = %d (vs %d) %s\n", + *mystruct->pn, DUMMY_SCALAR_VALUE2, + *mystruct->pn == DUMMY_SCALAR_VALUE2 ? "PASS" : "FAIL"); + } + + printf(" ps = %p (vs %p) %s\n", + mystruct->ps, &dummy_struct, + mystruct->ps == &dummy_struct ? "PASS" : "FAIL"); + if (mystruct->ps == &dummy_struct) + { + printf(" ps->n = %d (vs %d) %s\n", + mystruct->ps->n, DUMMY_SCALAR_VALUE3, + mystruct->ps->n == DUMMY_SCALAR_VALUE3 ? "PASS" : "FAIL"); + } + + printf(" pf = %p (vs %p) %s\n", + mystruct->pf, dummyfunc, + mystruct->pf == dummyfunc ? "PASS" : "FAIL"); + if (mystruct->pf == dummyfunc) + { + printf("Calling mystruct->pf()\n"); + mystruct->pf(); + } + + printf("Exit-ing\n"); + return 0; +} + +void dummyfunc(void) +{ + printf("In dummyfunc() -- PASS\n"); +} + + diff --git a/apps/examples/nxflat/tests/task/Makefile b/apps/examples/nxflat/tests/task/Makefile new file mode 100644 index 000000000..0881d4717 --- /dev/null +++ b/apps/examples/nxflat/tests/task/Makefile @@ -0,0 +1,79 @@ +############################################################################ +# examples/nxflat/tests/task/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = task + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -D $(BIN) $(ROMFS_DIR)/$(BIN) + + diff --git a/apps/examples/nxflat/tests/task/task.c b/apps/examples/nxflat/tests/task/task.c new file mode 100644 index 000000000..63e8188ed --- /dev/null +++ b/apps/examples/nxflat/tests/task/task.c @@ -0,0 +1,143 @@ +/**************************************************************************** + * examples/nxflat/tests/task/parent.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sched.h> +#include <semaphore.h> +#include <errno.h> + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static char child_name[] = "child"; +static char child_arg[] = "Hello from your parent!"; +static sem_t g_sem; + +#if CONFIG_TASK_NAME_SIZE == 0 +static char no_name[] = "<noname>"; +#endif + +/**************************************************************************** + * Privite Functions + ****************************************************************************/ + +/* NOTE: it is necessary for functions that are referred to by function pointers + * pointer to be declared with global scope (at least for ARM). Otherwise, + * a relocation type that is not supported by NXFLAT is generated by GCC. + */ + + int child_task(int argc, char **argv) +{ + printf("Child: execv was successful!\n"); + printf("Child: argc=%d\n", argc); + + if (argc != 2) + { + printf("Child: expected argc to be 2\n"); + printf("Child: Exit-ting with status=2\n"); + exit(2); + } + printf("Child: argv[0]=\"%s\"\n", argv[0]); + +#if CONFIG_TASK_NAME_SIZE == 0 + if (strcmp(argv[0], no_name) != 0) + { + printf("Child: expected argv[0] to be \"%s\"\n", no_name); + printf("Child: Exit-ting with status=3\n"); + exit(3); + } +#else + if (strncmp(argv[0], child_name, CONFIG_TASK_NAME_SIZE) != 0) + { + printf("Child: expected argv[0] to be \"%s\"\n", child_name); + printf("Child: Exit-ting with status=3\n"); + exit(3); + } +#endif + + printf("Child: argv[1]=\"%s\"\n", argv[1]); + + if (strcmp(argv[1], child_arg) != 0) + { + printf("Child: expected argv[1] to be \"%s\"\n", child_arg); + printf("Child: Exit-ting with status=4\n"); + exit(4); + } + + printf("Child: Exit-ting with status=0\n"); + sem_post(&g_sem); + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + pid_t parent_pid = getpid(); + char *child_argv[2]; + pid_t child_pid; + + printf("Parent: Started, pid=%d\n", parent_pid); + + sem_init(&g_sem, 0, 0); + + printf("Parent: Calling task_create()\n"); + + child_argv[0] = child_arg; + child_argv[1] = 0; + child_pid = task_create(child_name, 50, 512, child_task, (const char**)child_argv); + if (child_pid < 0) + { + printf("Parent: task_create failed: %d\n", errno); + } + + printf("Parent: Waiting for child (pid=%d)\n", child_pid); + sem_wait(&g_sem); + printf("Parent: Exit-ing\n"); + sem_destroy(&g_sem); + return 0; +} + diff --git a/apps/examples/nxhello/Makefile b/apps/examples/nxhello/Makefile new file mode 100644 index 000000000..84fb41775 --- /dev/null +++ b/apps/examples/nxhello/Makefile @@ -0,0 +1,105 @@ +############################################################################ +# apps/examples/nxhello/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttX NX Graphics Example. + +ASRCS = +CSRCS = nxhello_main.c nxhello_bkgd.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# NXHELLO built-in application info + +APPNAME = nxhello +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_NXHELLO_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/nxhello/nxhello.h b/apps/examples/nxhello/nxhello.h new file mode 100644 index 000000000..169285856 --- /dev/null +++ b/apps/examples/nxhello/nxhello.h @@ -0,0 +1,196 @@ +/**************************************************************************** + * examples/nxhello/nxhello.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_NXHELLO_NXHELLO_H +#define __APPS_EXAMPLES_NXHELLO_NXHELLO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <semaphore.h> + +#include <nuttx/nx/nxglib.h> +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxfonts.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_NX +# error "NX is not enabled (CONFIG_NX)" +#endif + +#ifndef CONFIG_EXAMPLES_NXHELLO_VPLANE +# define CONFIG_EXAMPLES_NXHELLO_VPLANE 0 +#endif + +#ifndef CONFIG_EXAMPLES_NXHELLO_BPP +# define CONFIG_EXAMPLES_NXHELLO_BPP 32 +#endif + +#ifndef CONFIG_EXAMPLES_NXHELLO_BGCOLOR +# if CONFIG_EXAMPLES_NXHELLO_BPP == 24 || CONFIG_EXAMPLES_NXHELLO_BPP == 32 +# define CONFIG_EXAMPLES_NXHELLO_BGCOLOR 0x007b68ee +# elif CONFIG_EXAMPLES_NXHELLO_BPP == 16 +# define CONFIG_EXAMPLES_NXHELLO_BGCOLOR 0x7b5d +# else +# define CONFIG_EXAMPLES_NXHELLO_BGCOLOR ' ' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NXHELLO_FONTID +# define CONFIG_EXAMPLES_NXHELLO_FONTID NXFONT_DEFAULT +#endif + +#ifndef CONFIG_EXAMPLES_NXHELLO_FONTCOLOR +# if CONFIG_EXAMPLES_NXHELLO_BPP == 24 || CONFIG_EXAMPLES_NXHELLO_BPP == 32 +# define CONFIG_EXAMPLES_NXHELLO_FONTCOLOR 0x00000000 +# elif CONFIG_EXAMPLES_NXHELLO_BPP == 16 +# define CONFIG_EXAMPLES_NXHELLO_FONTCOLOR 0x0000 +# else +# define CONFIG_EXAMPLES_NXHELLO_FONTCOLOR 'F' +# endif +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum exitcode_e +{ + NXEXIT_SUCCESS = 0, + NXEXIT_EXTINITIALIZE, + NXEXIT_FBINITIALIZE, + NXEXIT_FBGETVPLANE, + NXEXIT_LCDINITIALIZE, + NXEXIT_LCDGETDEV, + NXEXIT_NXOPEN, + NXEXIT_FONTOPEN, + NXEXIT_NXREQUESTBKGD, + NXEXIT_NXSETBGCOLOR +}; + +/* Describes one cached glyph bitmap */ + +struct nxhello_glyph_s +{ + uint8_t code; /* Character code */ + uint8_t height; /* Height of this glyph (in rows) */ + uint8_t width; /* Width of this glyph (in pixels) */ + uint8_t stride; /* Width of the glyph row (in bytes) */ + uint8_t usecnt; /* Use count */ + FAR uint8_t *bitmap; /* Allocated bitmap memory */ +}; + +/* Describes on character on the display */ + +struct nxhello_bitmap_s +{ + uint8_t code; /* Character code */ + uint8_t flags; /* See BMFLAGS_* */ + struct nxgl_point_s pos; /* Character position */ +}; + +struct nxhello_data_s +{ + /* The NX handles */ + + NXHANDLE hnx; + NXHANDLE hbkgd; + NXHANDLE hfont; + + /* The screen resolution */ + + nxgl_coord_t xres; + nxgl_coord_t yres; + + volatile bool havepos; + sem_t sem; + volatile int code; +}; + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/* NXHELLO state data */ + +extern struct nxhello_data_s g_nxhello; + +/* NX callback vtables */ + +extern const struct nx_callback_s g_bgcb; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXHELLO_EXTERNINIT +extern FAR NX_DRIVERTYPE *up_nxdrvinit(unsigned int devno); +#endif + +/* Background window interfaces */ + +extern void nxhello_hello(NXWINDOW hwnd); + +#endif /* __APPS_EXAMPLES_NXHELLO_NXHELLO_H */ diff --git a/apps/examples/nxhello/nxhello_bkgd.c b/apps/examples/nxhello/nxhello_bkgd.c new file mode 100644 index 000000000..93b7798e1 --- /dev/null +++ b/apps/examples/nxhello/nxhello_bkgd.c @@ -0,0 +1,443 @@ +/**************************************************************************** + * examples/nxhello/nxhello_bkgd.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <semaphore.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxglib.h> +#include <nuttx/nx/nxfonts.h> + +#include "nxhello.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Select renderer -- Some additional logic would be required to support + * pixel depths that are not directly addressable (1,2,4, and 24). + */ + +#if CONFIG_EXAMPLES_NXHELLO_BPP == 1 +# define RENDERER nxf_convert_1bpp +#elif CONFIG_EXAMPLES_NXHELLO_BPP == 2 +# define RENDERER nxf_convert_2bpp +#elif CONFIG_EXAMPLES_NXHELLO_BPP == 4 +# define RENDERER nxf_convert_4bpp +#elif CONFIG_EXAMPLES_NXHELLO_BPP == 8 +# define RENDERER nxf_convert_8bpp +#elif CONFIG_EXAMPLES_NXHELLO_BPP == 16 +# define RENDERER nxf_convert_16bpp +#elif CONFIG_EXAMPLES_NXHELLO_BPP == 24 +# define RENDERER nxf_convert_24bpp +#elif CONFIG_EXAMPLES_NXHELLO_BPP == 32 +# define RENDERER nxf_convert_32bpp +#else +# error "Unsupported CONFIG_EXAMPLES_NXHELLO_BPP" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void nxhello_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool morem, FAR void *arg); +static void nxhello_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg); +#ifdef CONFIG_NX_MOUSE +static void nxhello_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg); +#endif + +#ifdef CONFIG_NX_KBD +static void nxhello_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_hello[] = "Hello, World!"; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Background window call table */ + +const struct nx_callback_s g_bgcb = +{ + nxhello_redraw, /* redraw */ + nxhello_position /* position */ +#ifdef CONFIG_NX_MOUSE + , nxhello_mousein /* mousein */ +#endif +#ifdef CONFIG_NX_KBD + , nxhello_kbdin /* my kbdin */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxhello_redraw + ****************************************************************************/ + +static void nxhello_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool more, FAR void *arg) +{ + gvdbg("hwnd=%p rect={(%d,%d),(%d,%d)} more=%s\n", + hwnd, rect->pt1.x, rect->pt1.y, rect->pt2.x, rect->pt2.y, + more ? "true" : "false"); +} + +/**************************************************************************** + * Name: nxhello_position + ****************************************************************************/ + +static void nxhello_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg) +{ + /* Report the position */ + + gvdbg("hwnd=%p size=(%d,%d) pos=(%d,%d) bounds={(%d,%d),(%d,%d)}\n", + hwnd, size->w, size->h, pos->x, pos->y, + bounds->pt1.x, bounds->pt1.y, bounds->pt2.x, bounds->pt2.y); + + /* Have we picked off the window bounds yet? */ + + if (!g_nxhello.havepos) + { + /* Save the background window handle */ + + g_nxhello.hbkgd = hwnd; + + /* Save the window limits */ + + g_nxhello.xres = bounds->pt2.x + 1; + g_nxhello.yres = bounds->pt2.y + 1; + + g_nxhello.havepos = true; + sem_post(&g_nxhello.sem); + gvdbg("Have xres=%d yres=%d\n", g_nxhello.xres, g_nxhello.yres); + } +} + +/**************************************************************************** + * Name: nxhello_mousein + ****************************************************************************/ + +#ifdef CONFIG_NX_MOUSE +static void nxhello_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg) +{ + message("nxhello_mousein: hwnd=%p pos=(%d,%d) button=%02x\n", + hwnd, pos->x, pos->y, buttons); +} +#endif + +/**************************************************************************** + * Name: nxhello_kbdin + ****************************************************************************/ + +#ifdef CONFIG_NX_KBD +static void nxhello_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg) +{ + gvdbg("hwnd=%p nch=%d\n", hwnd, nch); + + /* In this example, there is no keyboard so a keyboard event is not + * expected. + */ + + message("nxhello_kbdin: Unexpected keyboard callback\n"); +} +#endif + +/**************************************************************************** + * Name: nxhello_center + ****************************************************************************/ + +static void nxhello_center(FAR struct nxgl_point_s *pos, + FAR const struct nx_font_s *fontset) +{ + FAR const struct nx_fontbitmap_s *fbm; + FAR uint8_t *ptr; + unsigned int width; + + /* Get the width of the collection of characters so that we can center the + * hello world message. + */ + + for (ptr = (uint8_t*)g_hello, width = 0; *ptr; ptr++) + { + /* Get the font bitmap for this character */ + + fbm = nxf_getbitmap(g_nxhello.hfont, *ptr); + if (fbm) + { + /* Add the font size */ + + width += fbm->metric.width + fbm->metric.xoffset; + } + else + { + /* Use the width of a space */ + + width += fontset->spwidth; + } + } + + /* Now we know how to center the string. Create a the position and + * the bounding box + */ + + pos->x = (g_nxhello.xres - width) / 2; + pos->y = (g_nxhello.yres - fontset->mxheight) / 2; +} + +/**************************************************************************** + * Name: nxhello_initglyph + ****************************************************************************/ + +static void nxhello_initglyph(FAR uint8_t *glyph, uint8_t height, + uint8_t width, uint8_t stride) +{ + FAR nxgl_mxpixel_t *ptr; +#if CONFIG_EXAMPLES_NXHELLO_BPP < 8 + nxgl_mxpixel_t pixel; +#endif + unsigned int row; + unsigned int col; + + /* Initialize the glyph memory to the background color */ + +#if CONFIG_EXAMPLES_NXHELLO_BPP < 8 + + pixel = CONFIG_EXAMPLES_NXHELLO_BGCOLOR; + +#if CONFIG_NX_NPLANES > 1 +# warning "More logic is needed for the case where CONFIG_NX_PLANES > 1" +#endif +# if CONFIG_EXAMPLES_NXHELLO_BPP == 1 + /* Pack 1-bit pixels into a 2-bits */ + + pixel &= 0x01; + pixel = (pixel) << 1 |pixel; + +# endif +# if CONFIG_EXAMPLES_NXHELLO_BPP < 4 + + /* Pack 2-bit pixels into a nibble */ + + pixel &= 0x03; + pixel = (pixel) << 2 |pixel; + +# endif + + /* Pack 4-bit nibbles into a byte */ + + pixel &= 0x0f; + pixel = (pixel) << 4 | pixel; + + ptr = (FAR nxgl_mxpixel_t *)glyph; + for (row = 0; row < fheight; row++) + { + for (col = 0; col < stride; col++) + { + /* Transfer the packed bytes into the buffer */ + + *ptr++ = pixel; + } + } + +#elif CONFIG_EXAMPLES_NXHELLO_BPP == 24 +# error "Additional logic is needed here for 24bpp support" + +#else /* CONFIG_EXAMPLES_NXHELLO_BPP = {8,16,32} */ + + ptr = (FAR nxgl_mxpixel_t *)glyph; + for (row = 0; row < height; row++) + { + /* Just copy the color value into the glyph memory */ + + for (col = 0; col < width; col++) + { + *ptr++ = CONFIG_EXAMPLES_NXHELLO_BGCOLOR; +#if CONFIG_NX_NPLANES > 1 +# warning "More logic is needed for the case where CONFIG_NX_PLANES > 1" +#endif + } + } +#endif +} + + /**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxhello_hello + * + * Description: + * Print "Hello, World!" in the center of the display. + * + ****************************************************************************/ + +void nxhello_hello(NXWINDOW hwnd) +{ + FAR const struct nx_font_s *fontset; + FAR const struct nx_fontbitmap_s *fbm; + FAR uint8_t *glyph; + FAR const char *ptr; + FAR struct nxgl_point_s pos; + FAR struct nxgl_rect_s dest; + FAR const void *src[CONFIG_NX_NPLANES]; + unsigned int glyphsize; + unsigned int mxstride; + int ret; + + /* Get information about the font we are going to use */ + + fontset = nxf_getfontset(g_nxhello.hfont); + + /* Allocate a bit of memory to hold the largest rendered font */ + + mxstride = (fontset->mxwidth * CONFIG_EXAMPLES_NXHELLO_BPP + 7) >> 3; + glyphsize = (unsigned int)fontset->mxheight * mxstride; + glyph = (FAR uint8_t*)malloc(glyphsize); + + /* NOTE: no check for failure to allocate the memory. In a real application + * you would need to handle that event. + */ + + /* Get a position so the the "Hello, World!" string will be centered on the + * display. + */ + + nxhello_center(&pos, fontset); + message("nxhello_hello: Position (%d,%d)\n", pos.x, pos.y); + + /* Now we can say "hello" in the center of the display. */ + + for (ptr = g_hello; *ptr; ptr++) + { + /* Get the bitmap font for this ASCII code */ + + fbm = nxf_getbitmap(g_nxhello.hfont, *ptr); + if (fbm) + { + uint8_t fheight; /* Height of this glyph (in rows) */ + uint8_t fwidth; /* Width of this glyph (in pixels) */ + uint8_t fstride; /* Width of the glyph row (in bytes) */ + + /* Get information about the font bitmap */ + + fwidth = fbm->metric.width + fbm->metric.xoffset; + fheight = fbm->metric.height + fbm->metric.yoffset; + fstride = (fwidth * CONFIG_EXAMPLES_NXHELLO_BPP + 7) >> 3; + + /* Initialize the glyph memory to the background color */ + + nxhello_initglyph(glyph, fheight, fwidth, fstride); + + /* Then render the glyph into the allocated memory */ + +#if CONFIG_NX_NPLANES > 1 +# warning "More logic is needed for the case where CONFIG_NX_PLANES > 1" +#endif + (void)RENDERER((FAR nxgl_mxpixel_t*)glyph, fheight, fwidth, + fstride, fbm, CONFIG_EXAMPLES_NXHELLO_FONTCOLOR); + + /* Describe the destination of the font with a rectangle */ + + dest.pt1.x = pos.x; + dest.pt1.y = pos.y; + dest.pt2.x = pos.x + fwidth - 1; + dest.pt2.y = pos.y + fheight - 1; + + /* Then put the font on the display */ + + src[0] = (FAR const void *)glyph; +#if CONFIG_NX_NPLANES > 1 +# warning "More logic is needed for the case where CONFIG_NX_PLANES > 1" +#endif + ret = nx_bitmap((NXWINDOW)hwnd, &dest, src, &pos, fstride); + if (ret < 0) + { + message("nxhello_write: nx_bitmapwindow failed: %d\n", errno); + } + + /* Skip to the right the width of the font */ + + pos.x += fwidth; + } + else + { + /* No bitmap (probably because the font is a space). Skip to the + * right the width of a space. + */ + + pos.x += fontset->spwidth; + } + } + + /* Free the allocated glyph */ + + free(glyph); +} diff --git a/apps/examples/nxhello/nxhello_main.c b/apps/examples/nxhello/nxhello_main.c new file mode 100644 index 000000000..e71df98d1 --- /dev/null +++ b/apps/examples/nxhello/nxhello_main.c @@ -0,0 +1,294 @@ +/**************************************************************************** + * examples/nxhello/nxhello_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <string.h> +#include <sched.h> +#include <pthread.h> +#include <errno.h> +#include <debug.h> + +#ifdef CONFIG_NX_LCDDRIVER +# include <nuttx/lcd/lcd.h> +#else +# include <nuttx/fb.h> +#endif + +#include <nuttx/arch.h> +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxglib.h> +#include <nuttx/nx/nxfonts.h> + +#include "nxhello.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ +/* If not specified, assume that the hardware supports one video plane */ + +#ifndef CONFIG_EXAMPLES_NXHELLO_VPLANE +# define CONFIG_EXAMPLES_NXHELLO_VPLANE 0 +#endif + +/* If not specified, assume that the hardware supports one LCD device */ + +#ifndef CONFIG_EXAMPLES_NXHELLO_DEVNO +# define CONFIG_EXAMPLES_NXHELLO_DEVNO 0 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct nxhello_data_s g_nxhello = +{ + NULL, /* hnx */ + NULL, /* hbkgd */ + NULL, /* hfont */ + 0, /* xres */ + 0, /* yres */ + false, /* havpos */ + { 0 }, /* sem */ + NXEXIT_SUCCESS /* exit code */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxhello_initialize + ****************************************************************************/ + +static inline int nxhello_initialize(void) +{ + FAR NX_DRIVERTYPE *dev; + +#if defined(CONFIG_EXAMPLES_NXHELLO_EXTERNINIT) + /* Use external graphics driver initialization */ + + message("nxhello_initialize: Initializing external graphics device\n"); + dev = up_nxdrvinit(CONFIG_EXAMPLES_NXHELLO_DEVNO); + if (!dev) + { + message("nxhello_initialize: up_nxdrvinit failed, devno=%d\n", + CONFIG_EXAMPLES_NXHELLO_DEVNO); + g_nxhello.code = NXEXIT_EXTINITIALIZE; + return ERROR; + } + +#elif defined(CONFIG_NX_LCDDRIVER) + int ret; + + /* Initialize the LCD device */ + + message("nxhello_initialize: Initializing LCD\n"); + ret = up_lcdinitialize(); + if (ret < 0) + { + message("nxhello_initialize: up_lcdinitialize failed: %d\n", -ret); + g_nxhello.code = NXEXIT_LCDINITIALIZE; + return ERROR; + } + + /* Get the device instance */ + + dev = up_lcdgetdev(CONFIG_EXAMPLES_NXHELLO_DEVNO); + if (!dev) + { + message("nxhello_initialize: up_lcdgetdev failed, devno=%d\n", CONFIG_EXAMPLES_NXHELLO_DEVNO); + g_nxhello.code = NXEXIT_LCDGETDEV; + return ERROR; + } + + /* Turn the LCD on at 75% power */ + + (void)dev->setpower(dev, ((3*CONFIG_LCD_MAXPOWER + 3)/4)); +#else + int ret; + + /* Initialize the frame buffer device */ + + message("nxhello_initialize: Initializing framebuffer\n"); + ret = up_fbinitialize(); + if (ret < 0) + { + message("nxhello_initialize: up_fbinitialize failed: %d\n", -ret); + g_nxhello.code = NXEXIT_FBINITIALIZE; + return ERROR; + } + + dev = up_fbgetvplane(CONFIG_EXAMPLES_NXHELLO_VPLANE); + if (!dev) + { + message("nxhello_initialize: up_fbgetvplane failed, vplane=%d\n", CONFIG_EXAMPLES_NXHELLO_VPLANE); + g_nxhello.code = NXEXIT_FBGETVPLANE; + return ERROR; + } +#endif + + /* Then open NX */ + + message("nxhello_initialize: Open NX\n"); + g_nxhello.hnx = nx_open(dev); + if (!g_nxhello.hnx) + { + message("nxhello_initialize: nx_open failed: %d\n", errno); + g_nxhello.code = NXEXIT_NXOPEN; + return ERROR; + } + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start/nxhello_main + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXHELLO_BUILTIN +# define MAIN_NAME nxhello_main +# define MAIN_NAME_STRING "nxhello_main" +#else +# define MAIN_NAME user_start +# define MAIN_NAME_STRING "user_start" +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + nxgl_mxpixel_t color; + int ret; + + /* Initialize NX */ + + ret = nxhello_initialize(); + message(MAIN_NAME_STRING ": NX handle=%p\n", g_nxhello.hnx); + if (!g_nxhello.hnx || ret < 0) + { + message(MAIN_NAME_STRING ": Failed to get NX handle: %d\n", errno); + g_nxhello.code = NXEXIT_NXOPEN; + goto errout; + } + + /* Get the default font handle */ + + g_nxhello.hfont = nxf_getfonthandle(CONFIG_EXAMPLES_NXHELLO_FONTID); + if (!g_nxhello.hfont) + { + message(MAIN_NAME_STRING ": Failed to get font handle: %d\n", errno); + g_nxhello.code = NXEXIT_FONTOPEN; + goto errout; + } + + /* Set the background to the configured background color */ + + message(MAIN_NAME_STRING ": Set background color=%d\n", + CONFIG_EXAMPLES_NXHELLO_BGCOLOR); + + color = CONFIG_EXAMPLES_NXHELLO_BGCOLOR; + ret = nx_setbgcolor(g_nxhello.hnx, &color); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_setbgcolor failed: %d\n", errno); + g_nxhello.code = NXEXIT_NXSETBGCOLOR; + goto errout_with_nx; + } + + /* Get the background window */ + + ret = nx_requestbkgd(g_nxhello.hnx, &g_bgcb, NULL); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_setbgcolor failed: %d\n", errno); + g_nxhello.code = NXEXIT_NXREQUESTBKGD; + goto errout_with_nx; + } + + /* Wait until we have the screen resolution. We'll have this immediately + * unless we are dealing with the NX server. + */ + + while (!g_nxhello.havepos) + { + (void)sem_wait(&g_nxhello.sem); + } + message(MAIN_NAME_STRING ": Screen resolution (%d,%d)\n", g_nxhello.xres, g_nxhello.yres); + + /* Now, say hello and exit, sleeping a little before each. */ + + sleep(1); + nxhello_hello(g_nxhello.hbkgd); + sleep(1); + + /* Release background */ + + (void)nx_releasebkgd(g_nxhello.hbkgd); + + /* Close NX */ + +errout_with_nx: + message(MAIN_NAME_STRING ": Close NX\n"); + nx_close(g_nxhello.hnx); +errout: + return g_nxhello.code; +} diff --git a/apps/examples/nximage/Makefile b/apps/examples/nximage/Makefile new file mode 100755 index 000000000..4e0822687 --- /dev/null +++ b/apps/examples/nximage/Makefile @@ -0,0 +1,105 @@ +############################################################################ +# apps/examples/nximage/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttX NX Graphics Example. + +ASRCS = +CSRCS = nximage_main.c nximage_bkgd.c nximage_bitmap.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# NXIMAGE built-in application info + +APPNAME = nximage +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_NXIMAGE_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/nximage/nximage.h b/apps/examples/nximage/nximage.h new file mode 100755 index 000000000..117eff671 --- /dev/null +++ b/apps/examples/nximage/nximage.h @@ -0,0 +1,219 @@ +/**************************************************************************** + * examples/nximage/nximage.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_NXIMAGE_NXIMAGE_H +#define __APPS_EXAMPLES_NXIMAGE_NXIMAGE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <semaphore.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxglib.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_NX +# error "NX is not enabled (CONFIG_NX)" +#endif + +#ifndef CONFIG_EXAMPLES_NXIMAGE_VPLANE +# define CONFIG_EXAMPLES_NXIMAGE_VPLANE 0 +#endif + +#ifndef CONFIG_EXAMPLES_NXIMAGE_BPP +# define CONFIG_EXAMPLES_NXIMAGE_BPP 16 +#endif + +#if defined(CONFIG_EXAMPLES_NXIMAGE_XSCALEp5) +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE1p0 +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE1p5 +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE2p0 +#elif defined(CONFIG_EXAMPLES_NXIMAGE_XSCALE1p5) +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALEp5 +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE1p0 +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE2p0 +#elif defined(CONFIG_EXAMPLES_NXIMAGE_XSCALE2p0) +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALEp5 +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE1p0 +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE1p5 +#else +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALEp5 +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE1p0 +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE1p5 +# undef CONFIG_EXAMPLES_NXIMAGE_XSCALE2p0 +# define CONFIG_EXAMPLES_NXIMAGE_XSCALE1p0 1 +#endif + +#if defined(CONFIG_EXAMPLES_NXIMAGE_YSCALEp5) +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE1p0 +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5 +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE2p0 +#elif defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5) +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALEp5 +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE1p0 +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE2p0 +#elif defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE2p0) +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALEp5 +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE1p0 +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5 +#else +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALEp5 +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE1p0 +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5 +# undef CONFIG_EXAMPLES_NXIMAGE_YSCALE2p0 +# define CONFIG_EXAMPLES_NXIMAGE_YSCALE1p0 1 +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +/* Image Information ********************************************************/ + +#define IMAGE_HEIGHT 160 /* Number of rows in the raw image */ +#define IMAGE_WIDTH 160 /* Number of columns in the raw image */ + +#if defined(CONFIG_EXAMPLES_NXIMAGE_XSCALEp5) +# define SCALED_WIDTH 80 /* Number of columns in the scaled image */ +#elif defined(CONFIG_EXAMPLES_NXIMAGE_XSCALE1p5) +# define SCALED_WIDTH 240 /* Number of columns in the scaled image */ +#elif defined(CONFIG_EXAMPLES_NXIMAGE_XSCALE2p0) +# define SCALED_WIDTH 320 /* Number of columns in the scaled image */ +#else +# define SCALED_WIDTH 160 /* Number of columns in the scaled image */ +#endif + +#if defined(CONFIG_EXAMPLES_NXIMAGE_YSCALEp5) +# define SCALED_HEIGHT 80 /* Number of rows in the scaled image */ +#elif defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5) +# define SCALED_HEIGHT 240 /* Number of rows in the scaled image */ +#elif defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE2p0) +# define SCALED_HEIGHT 320 /* Number of rows in the scaled image */ +#else +# define SCALED_HEIGHT 160 /* Number of rows in the scaled image */ +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum exitcode_e +{ + NXEXIT_SUCCESS = 0, + NXEXIT_EXTINITIALIZE, + NXEXIT_FBINITIALIZE, + NXEXIT_FBGETVPLANE, + NXEXIT_LCDINITIALIZE, + NXEXIT_LCDGETDEV, + NXEXIT_NXOPEN, + NXEXIT_NXREQUESTBKGD, + NXEXIT_NXSETBGCOLOR +}; + +struct nximage_data_s +{ + /* The NX handles */ + + NXHANDLE hnx; + NXHANDLE hbkgd; + + /* The screen resolution */ + + nxgl_coord_t xres; + nxgl_coord_t yres; + + volatile bool havepos; + sem_t sem; + volatile int code; +}; + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/* NXIMAGE state data */ + +extern struct nximage_data_s g_nximage; + +/* NX callback vtables */ + +extern const struct nx_callback_s g_bgcb; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXIMAGE_EXTERNINIT +extern FAR NX_DRIVERTYPE *up_nxdrvinit(unsigned int devno); +#endif + +/* Background window interfaces */ + +extern void nximage_image(NXWINDOW hwnd); + +/* Image interfaces */ + +extern nxgl_mxpixel_t nximage_bgcolor(void); +extern nxgl_mxpixel_t nximage_avgcolor(nxgl_mxpixel_t color1, nxgl_mxpixel_t color2); +extern void nximage_blitrow(FAR nxgl_mxpixel_t *run, FAR const void **state); + +#endif /* __APPS_EXAMPLES_NXIMAGE_NXIMAGE_H */ diff --git a/apps/examples/nximage/nximage_bitmap.c b/apps/examples/nximage/nximage_bitmap.c new file mode 100644 index 000000000..6b0d13718 --- /dev/null +++ b/apps/examples/nximage/nximage_bitmap.c @@ -0,0 +1,3711 @@ +/******************************************************************************************** + * examples/nximage/nximage_bitmap.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ********************************************************************************************/ + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <assert.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxglib.h> + +#include "nximage.h" + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ + +#if CONFIG_EXAMPLES_NXIMAGE_BPP == 24 + +# ifdef CONFIG_EXAMPLES_NXIMAGE_GREYSCALE +# error "24-bit greyscale not supported" +# endif + +# define IMAGE_NLUTCODES 164 /* Number of unique RGB colors in the image */ + +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 16 + +# ifdef CONFIG_EXAMPLES_NXIMAGE_GREYSCALE +# error "16-bit greyscale not supported" +# endif + +# define IMAGE_NLUTCODES 141 /* Number of unique RGB colors in the image */ + +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 8 + +# ifdef CONFIG_EXAMPLES_NXIMAGE_GREYSCALE +# define IMAGE_NLUTCODES 116 /* Number of unique greyscale levels in the image */ +# else +# define IMAGE_NLUTCODES 27 /* Number of unique RGB colors in the image */ +# endif + +#else +# error "Unsupport pixel format" +#endif + +/******************************************************************************************** + * Private Types + ********************************************************************************************/ + +struct pix_run_s +{ + uint8_t npix; /* Number of pixels */ + uint8_t code; /* Pixel RGB code */ +}; + +/******************************************************************************************** + * Private Data + ********************************************************************************************/ +/* RGB24 (8-8-8) Colors */ + +#if CONFIG_EXAMPLES_NXIMAGE_BPP == 24 + +static const nxgl_mxpixel_t g_lut[IMAGE_NLUTCODES] = +{ + 0x000000, 0x0a0804, 0x382616, 0x390c0f, 0x390d0f, 0x0a0203, 0x390b0e, 0x3a0d0f, /* Codes 0-7 */ + 0x350d0e, 0x1d0709, 0x24090b, 0x230f0d, 0x3b2817, 0x341511, 0x230a0b, 0x3a2817, /* Codes 8-15 */ + 0x350c0e, 0x1e1c1a, 0x3c3934, 0x390a0d, 0x0b0a09, 0x3c3933, 0x3b2321, 0x3d3d37, /* Codes 16-23 */ + 0x3c3b36, 0x38090b, 0x312e2a, 0x3c312d, 0x391516, 0x3c3c36, 0x3d3c36, 0x241212, /* Codes 24-31 */ + 0x1f0a0b, 0x1f0a0a, 0x1e090a, 0x2d0b0d, 0x3c3833, 0x3d3a36, 0x322f2a, 0x261f16, /* Codes 32-39 */ + 0x2f2617, 0x18130b, 0x3f3e38, 0x1e0507, 0x210a0b, 0x250a0c, 0x3f3f3f, 0x3d3a35, /* Codes 40-47 */ + 0x2e2414, 0x080704, 0x3e3b36, 0x2f2517, 0x3b2423, 0x2f211f, 0x3c3832, 0x363026, /* Codes 48-55 */ + 0x3e3c3a, 0x362f25, 0x390c0e, 0x3b2f2c, 0x3f3e3d, 0x3e3c39, 0x3b0d0f, 0x0a0805, /* Codes 56-63 */ + 0x2f2516, 0x2b1e14, 0x2d2114, 0x20080a, 0x2d0a0d, 0x3d3934, 0x32291c, 0x360d0f, /* Codes 64-71 */ + 0x2c201e, 0x2e2415, 0x2d2115, 0x1e070a, 0x3b2917, 0x3f3d37, 0x1e0406, 0x200a0b, /* Codes 72-79 */ + 0x340b0e, 0x2e0b0d, 0x220607, 0x3c2322, 0x3c3831, 0x373126, 0x1d0306, 0x2c2014, /* Codes 80-87 */ + 0x20090a, 0x030001, 0x1d090a, 0x3d0e10, 0x3b090c, 0x270b0c, 0x2d211f, 0x0a0703, /* Codes 88-95 */ + 0x382414, 0x39080c, 0x3e3c36, 0x2d1e1d, 0x1c0204, 0x1b0002, 0x230609, 0x1f0708, /* Codes 96-103 */ + 0x24080b, 0x342614, 0x3c3935, 0x342716, 0x38100e, 0x391210, 0x3c3731, 0x3e3d37, /* Codes 104-111 */ + 0x3a090c, 0x2b0b0d, 0x2e1e12, 0x381210, 0x3a2120, 0x23090b, 0x2f0c0d, 0x1c0709, /* Codes 112-119 */ + 0x1d0405, 0x380a0d, 0x3b0b0d, 0x2d090b, 0x1e0708, 0x340a0c, 0x230709, 0x2d1e1c, /* Codes 120-127 */ + 0x0a0001, 0x3c3a35, 0x351f13, 0x1e080a, 0x2c2115, 0x170a08, 0x1f0608, 0x2c1f13, /* Codes 128-135 */ + 0x340c0e, 0x3c0d10, 0x32080a, 0x3d3c37, 0x23100d, 0x3b3526, 0x38070b, 0x2b2014, /* Codes 136-143 */ + 0x3a0c0f, 0x2a1e1c, 0x070001, 0x0d0c0b, 0x19140c, 0x16110b, 0x322a1d, 0x3f3e3e, /* Codes 144-151 */ + 0x3e3b37, 0x37302c, 0x2f2c28, 0x39352d, 0x201e1c, 0x2a261f, 0x3c3d37, 0x2b080a, /* Codes 152-159 */ + 0x1d0608, 0x260a0c, 0x2b110e, 0x381f14 /* Codes 160-163 */ +}; + +/* RGB16 (565) Colors (four of the colors in this map are duplicates) */ + +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 16 + +static const nxgl_mxpixel_t g_lut[IMAGE_NLUTCODES] = +{ + 0x0000, 0x1105, 0x5cdc, 0x399c, 0x41bc, 0x0845, 0x397c, 0x39bc, 0x41bd, 0x39ba, /* Codes 0-9 */ + 0x28ee, 0x3132, 0x31f2, 0x5d1d, 0x42ba, 0x3152, 0x399a, 0x6b8f, 0xd73e, 0x315c, /* Codes 10-19 */ + 0x2945, 0x8c7d, 0xe7be, 0xdf7e, 0x313c, 0xadd9, 0xb63e, 0x5abd, 0xdf9e, 0xdf9f, /* Codes 20-29 */ + 0x4a52, 0x2950, 0x292f, 0x3176, 0xcf1e, 0xdf5f, 0xadf9, 0x5bf3, 0x5cd8, 0x326c, /* Codes 30-39 */ + 0xe7df, 0x18af, 0x3153, 0xdf5e, 0xffff, 0x5497, 0x10e4, 0xdf7f, 0x5cb8, 0x8c9d, /* Codes 40-49 */ + 0x8437, 0x9e1b, 0xef9f, 0x9dfb, 0xb5fe, 0xffdf, 0x41be, 0x53d6, 0x5436, 0x2910, /* Codes 50-59 */ + 0x3156, 0x7539, 0x39bb, 0x7c16, 0x95fb, 0x28ef, 0x653d, 0xe7bf, 0x188f, 0x397a, /* Codes 60-69 */ + 0x3977, 0x20d1, 0x8c7e, 0xe79f, 0x9e3b, 0x186e, 0x5416, 0x2930, 0x0801, 0x41de, /* Codes 70-79 */ + 0x313d, 0x3173, 0x7c36, 0x08e5, 0x549c, 0xd75f, 0x311c, 0x73d6, 0x3150, 0x315d, /* Codes 80-89 */ + 0x104e, 0x080e, 0x20f0, 0x2912, 0x54da, 0xdf3e, 0x5cfa, 0x3a1c, 0x425c, 0xcefe, /* Codes 90-99 */ + 0x4bd7, 0x843d, 0x2932, 0x3997, 0xf7df, 0x397d, 0x2936, 0x20ef, 0x315a, 0x20f1, /* Codes 100-109 */ + 0x0005, 0xd75e, 0x53fa, 0x290f, 0x214b, 0x20cf, 0x4bf6, 0x2919, 0x3212, 0x9ebd, /* Codes 110-119 */ + 0x28fc, 0x5415, 0x399d, 0x73d5, 0x0804, 0x3187, 0x328d, 0x2a2b, 0x7559, 0xe77f, /* Codes 120-129 */ + 0xb61c, 0x3186, 0xa598, 0xbebd, 0x73d0, 0x84d5, 0x5cb7, 0x2916, 0x20ce, 0x3a35, /* Codes 130-139 */ + 0x53fc /* Codes 140-140 */ +}; + +/* 8-bit color lookups. NOTE: This is really dumb! The lookup index is 8-bits and it used + * to lookup an 8-bit value. There is no savings in that! It would be better to just put + * the 8-bit color/greyscale value in the run-length encoded image and save the cost of these + * pointless lookups. But these p;ointless lookups do make the logic compatible with the + * 16- and 24-bit types. + */ + +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 8 +# ifdef CONFIG_EXAMPLES_NXIMAGE_GREYSCALE + +/* 8-bit Greyscale */ + +static const uint8_t g_lut[IMAGE_NLUTCODES] = +{ + 0x00, 0x19, 0x8b, 0x46, 0x4a, 0x0b, 0x8d, 0x41, 0x44, 0x27, 0x32, 0x92, 0x59, 0x34, 0x6d, 0xdb, /* Codes 0-15 */ + 0x3f, 0x26, 0x91, 0xec, 0xe5, 0x39, 0xb4, 0xc0, 0x62, 0xe6, 0x4c, 0x2f, 0x2e, 0x3c, 0xda, 0xe4, /* Codes 16-31 */ + 0x72, 0x86, 0xed, 0x1d, 0x35, 0xe2, 0xfc, 0xe3, 0x7d, 0x16, 0x97, 0x87, 0xee, 0xb2, 0x42, 0xbc, /* Codes 32-47 */ + 0xf6, 0x4b, 0x1c, 0x70, 0x90, 0x77, 0x2c, 0xdf, 0x96, 0x29, 0x45, 0x7f, 0x81, 0xb1, 0x28, 0xea, /* Codes 48-63 */ + 0x40, 0x3d, 0x23, 0x95, 0xe9, 0xd6, 0xb7, 0x2d, 0x02, 0x3a, 0x85, 0x17, 0x82, 0xe7, 0x7b, 0x33, /* Codes 64-79 */ + 0x0e, 0x25, 0x84, 0xe0, 0x8c, 0x4d, 0x56, 0x1e, 0x3b, 0x6e, 0x31, 0x3e, 0xf3, 0x1a, 0x20, 0x04, /* Codes 80-95 */ + 0xe1, 0x74, 0x2a, 0x79, 0x21, 0x71, 0xc4, 0x76, 0x48, 0x98, 0xf7, 0x94, 0xe8, 0xbe, 0xac, 0xc9, /* Codes 96-111 */ + 0x75, 0x8e, 0x49, 0x7a /* Codes 112-115 */ +}; + +# else /* CONFIG_EXAMPLES_NXIMAGE_GREYSCALE */ + +/* RGB8 (332) Colors */ + +static const nxgl_mxpixel_t g_lut[IMAGE_NLUTCODES] = +{ + 0x00, 0x25, 0x77, 0x4b, 0x01, 0x47, 0x26, 0x4a, 0x4f, 0x72, 0xdf, 0x93, 0xff, 0x27, 0xbb, 0xdb, /* Codes 0-15 */ + 0x6f, 0x29, 0x53, 0x97, 0x73, 0x22, 0x05, 0x02, 0x57, 0xbf, 0x4e /* Codes 16-26 */ +}; + +# endif +#else +# error "Unsupport pixel format" +#endif + +#if CONFIG_EXAMPLES_NXIMAGE_BPP == 24 + +static const struct pix_run_s g_nuttx[] = +{ + { 76, 0}, { 1, 1}, { 1, 2}, { 1, 3}, { 4, 4}, { 1, 5}, { 76, 0}, /* Row 0 */ + { 75, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 2, 7}, { 3, 4}, { 1, 5}, /* Row 1 */ + { 75, 0}, + { 74, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 9}, { 1, 10}, /* Row 2 */ + { 1, 7}, { 3, 4}, { 1, 5}, { 74, 0}, + { 73, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 12}, /* Row 3 */ + { 1, 13}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 73, 0}, + { 72, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 4 */ + { 1, 6}, { 1, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 72, 0}, + { 71, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 5 */ + { 1, 6}, { 3, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 71, 0}, + { 70, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 6 */ + { 1, 6}, { 5, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 70, 0}, + { 69, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 7 */ + { 1, 6}, { 7, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 69, 0}, + { 68, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 8 */ + { 1, 6}, { 9, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 68, 0}, + { 67, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 9 */ + { 1, 6}, { 11, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 67, 0}, + { 66, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 10 */ + { 1, 6}, { 13, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 66, 0}, + { 65, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 11 */ + { 1, 6}, { 15, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 65, 0}, + { 64, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 12 */ + { 1, 6}, { 17, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 64, 0}, + { 63, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 13 */ + { 1, 6}, { 19, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 63, 0}, + { 62, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 14 */ + { 1, 6}, { 21, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 62, 0}, + { 61, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 15 */ + { 1, 6}, { 23, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 61, 0}, + { 60, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 16 */ + { 1, 6}, { 25, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 60, 0}, + { 59, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 17 */ + { 1, 6}, { 27, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 59, 0}, + { 58, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 18 */ + { 1, 6}, { 29, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 26, 0}, + { 1, 17}, { 5, 18}, { 1, 17}, { 25, 0}, + { 57, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 19 */ + { 1, 6}, { 10, 4}, { 5, 19}, { 16, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, + { 1, 5}, { 23, 0}, { 1, 20}, { 1, 18}, { 1, 21}, { 5, 18}, { 1, 21}, { 1, 18}, + { 1, 20}, { 23, 0}, + { 56, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, /* Row 20 */ + { 1, 6}, { 9, 4}, { 1, 19}, { 1, 22}, { 1, 23}, { 3, 24}, { 1, 23}, { 1, 22}, + { 1, 25}, { 15, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 22, 0}, + { 11, 18}, { 1, 20}, { 22, 0}, + { 23, 0}, { 1, 17}, { 5, 18}, { 1, 26}, { 25, 0}, { 1, 1}, { 1, 2}, { 1, 6}, /* Row 21 */ + { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 9, 4}, { 1, 19}, { 1, 27}, + { 1, 21}, { 5, 18}, { 1, 21}, { 1, 23}, { 1, 28}, { 15, 4}, { 1, 16}, { 1, 14}, + { 1, 7}, { 3, 4}, { 1, 5}, { 20, 0}, { 1, 17}, { 1, 21}, { 11, 18}, { 1, 20}, + { 21, 0}, + { 21, 0}, { 1, 20}, { 1, 18}, { 1, 21}, { 5, 18}, { 1, 21}, { 1, 18}, { 1, 20}, /* Row 22 */ + { 22, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 9, 4}, { 1, 19}, { 1, 27}, { 1, 21}, { 8, 18}, { 1, 29}, { 1, 28}, + { 4, 7}, { 11, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 19, 0}, + { 14, 18}, { 21, 0}, + { 21, 0}, { 11, 18}, { 1, 20}, { 20, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, /* Row 23 */ + { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 10, 4}, { 1, 22}, { 1, 21}, { 10, 18}, + { 1, 30}, { 1, 31}, { 1, 32}, { 1, 33}, { 1, 34}, { 1, 35}, { 1, 7}, { 10, 4}, + { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 17, 0}, { 1, 17}, { 1, 21}, + { 4, 18}, { 1, 36}, { 2, 37}, { 1, 36}, { 4, 18}, { 1, 21}, { 1, 17}, { 20, 0}, + { 20, 0}, { 1, 38}, { 1, 21}, { 11, 18}, { 1, 39}, { 4, 40}, { 1, 41}, { 13, 0}, /* Row 24 */ + { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, + { 10, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 3, 36}, { 5, 18}, { 1, 42}, { 1, 43}, + { 3, 44}, { 1, 45}, { 1, 7}, { 10, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, + { 1, 5}, { 16, 0}, { 5, 18}, { 1, 37}, { 4, 46}, { 1, 37}, { 4, 18}, { 1, 47}, + { 1, 48}, { 1, 49}, { 18, 0}, + { 19, 0}, { 1, 17}, { 1, 21}, { 12, 18}, { 1, 50}, { 1, 48}, { 3, 40}, { 1, 51}, /* Row 25 */ + { 1, 40}, { 11, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 11, 4}, { 1, 52}, { 1, 21}, { 3, 18}, { 1, 37}, { 3, 46}, + { 1, 37}, { 4, 18}, { 1, 21}, { 1, 53}, { 4, 44}, { 1, 45}, { 1, 7}, { 10, 4}, + { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 14, 0}, { 1, 17}, { 1, 21}, + { 3, 18}, { 1, 54}, { 6, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 55}, { 1, 40}, + { 1, 49}, { 17, 0}, + { 19, 0}, { 5, 18}, { 1, 54}, { 2, 56}, { 1, 37}, { 5, 18}, { 1, 21}, { 1, 57}, /* Row 26 */ + { 4, 40}, { 1, 51}, { 1, 41}, { 9, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, + { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 11, 4}, { 1, 58}, { 1, 59}, { 3, 18}, + { 1, 21}, { 1, 60}, { 4, 46}, { 1, 37}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, + { 1, 45}, { 1, 7}, { 10, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, + { 13, 0}, { 5, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 4, 18}, { 1, 57}, { 2, 40}, + { 1, 49}, { 16, 0}, + { 18, 0}, { 1, 17}, { 1, 21}, { 3, 18}, { 1, 37}, { 4, 46}, { 1, 37}, { 5, 18}, /* Row 27 */ + { 1, 50}, { 1, 48}, { 5, 40}, { 8, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, + { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 12, 4}, { 1, 19}, { 1, 24}, { 3, 18}, + { 1, 37}, { 6, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, + { 11, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 11, 0}, { 1, 17}, + { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 57}, { 3, 40}, + { 16, 0}, + { 18, 0}, { 4, 18}, { 1, 54}, { 5, 46}, { 1, 60}, { 1, 36}, { 4, 18}, { 1, 21}, /* Row 28 */ + { 1, 57}, { 4, 40}, { 1, 51}, { 1, 41}, { 6, 0}, { 1, 1}, { 1, 2}, { 1, 6}, + { 1, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 13, 4}, { 1, 19}, { 1, 24}, + { 3, 18}, { 1, 61}, { 6, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, + { 1, 34}, { 1, 62}, { 11, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, + { 10, 0}, { 5, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 55}, + { 2, 40}, { 1, 51}, { 1, 41}, { 15, 0}, + { 18, 0}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 5, 18}, { 1, 50}, { 1, 48}, /* Row 29 */ + { 5, 40}, { 5, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 14, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, + { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 12, 4}, { 1, 16}, + { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 8, 0}, { 1, 17}, { 1, 21}, { 3, 18}, + { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 4, 40}, { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 57}, /* Row 30 */ + { 4, 40}, { 1, 51}, { 1, 41}, { 3, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, + { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 15, 4}, { 1, 19}, { 1, 24}, { 2, 18}, + { 1, 36}, { 8, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, + { 1, 62}, { 12, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 7, 0}, + { 5, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 57}, { 5, 40}, + { 1, 63}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 56}, { 5, 18}, { 1, 50}, { 1, 48}, /* Row 31 */ + { 5, 40}, { 2, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 16, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 9, 46}, + { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 13, 4}, { 1, 16}, + { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 5, 0}, { 1, 17}, { 1, 21}, { 3, 18}, + { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 5, 40}, { 1, 41}, + { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 9, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 57}, /* Row 32 */ + { 4, 40}, { 1, 51}, { 1, 41}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 4}, { 1, 8}, + { 1, 11}, { 1, 15}, { 1, 6}, { 17, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, + { 9, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, + { 13, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 4, 0}, { 5, 18}, + { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 57}, { 6, 40}, { 1, 63}, + { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 9, 46}, { 1, 56}, { 5, 18}, { 1, 50}, { 1, 48}, /* Row 33 */ + { 3, 40}, { 1, 64}, { 1, 65}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 18, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 10, 46}, + { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 14, 4}, { 1, 16}, + { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 2, 0}, { 1, 17}, { 1, 21}, { 3, 18}, + { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 10, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 57}, /* Row 34 */ + { 2, 40}, { 1, 64}, { 1, 66}, { 1, 67}, { 1, 68}, { 1, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 19, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 10, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 14, 4}, + { 1, 16}, { 1, 14}, { 1, 7}, { 3, 4}, { 1, 5}, { 1, 0}, { 5, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 69}, { 1, 70}, { 5, 40}, { 1, 51}, { 1, 41}, + { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 10, 46}, { 1, 56}, { 5, 18}, { 1, 50}, { 1, 48}, /* Row 35 */ + { 1, 64}, { 1, 66}, { 1, 67}, { 1, 44}, { 1, 34}, { 1, 71}, { 1, 11}, { 1, 15}, + { 1, 6}, { 20, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 11, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 15, 4}, { 1, 16}, { 1, 14}, + { 1, 7}, { 3, 4}, { 1, 72}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, + { 4, 18}, { 1, 50}, { 1, 73}, { 6, 40}, { 16, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 11, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 57}, /* Row 36 */ + { 1, 74}, { 1, 67}, { 3, 44}, { 1, 75}, { 1, 76}, { 1, 6}, { 21, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 11, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, + { 4, 44}, { 1, 34}, { 1, 62}, { 15, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 1, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 16, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 11, 46}, { 1, 56}, { 5, 18}, { 1, 77}, { 1, 78}, /* Row 37 */ + { 4, 44}, { 1, 79}, { 1, 80}, { 22, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, + { 12, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 16, 4}, + { 1, 16}, { 1, 14}, { 1, 7}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 12, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, /* Row 38 */ + { 5, 44}, { 1, 81}, { 22, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 12, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 16, 4}, + { 1, 16}, { 1, 82}, { 1, 23}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 12, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, /* Row 39 */ + { 4, 44}, { 1, 34}, { 1, 62}, { 21, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, + { 13, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 17, 4}, + { 1, 83}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, + { 1, 48}, { 6, 40}, { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 13, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, /* Row 40 */ + { 5, 44}, { 1, 35}, { 21, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 13, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 15, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 13, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, /* Row 41 */ + { 4, 44}, { 1, 34}, { 1, 62}, { 20, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, + { 14, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 15, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, + { 1, 48}, { 6, 40}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 14, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, /* Row 42 */ + { 5, 44}, { 1, 35}, { 20, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 14, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 13, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 14, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, /* Row 43 */ + { 4, 44}, { 1, 34}, { 1, 62}, { 19, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, + { 7, 46}, { 1, 61}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, + { 1, 35}, { 13, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, + { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 15, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, /* Row 44 */ + { 5, 44}, { 1, 35}, { 19, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, + { 1, 84}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, + { 1, 62}, { 11, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 61}, { 6, 46}, { 1, 56}, { 5, 18}, /* Row 45 */ + { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 18, 4}, { 1, 19}, { 1, 24}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 11, 4}, { 1, 22}, { 1, 21}, { 3, 18}, + { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 84}, { 7, 46}, { 1, 54}, { 4, 18}, /* Row 46 */ + { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 18, 4}, { 1, 19}, { 1, 24}, { 2, 18}, + { 1, 36}, { 7, 46}, { 1, 36}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 9, 4}, { 1, 25}, { 1, 23}, { 4, 18}, + { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 57}, { 5, 40}, { 1, 51}, + { 1, 41}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 1, 56}, { 6, 46}, { 1, 56}, /* Row 47 */ + { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 17, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 1, 18}, { 1, 56}, { 7, 46}, + { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 9, 4}, { 1, 22}, + { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, + { 6, 40}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 1, 54}, { 7, 46}, { 1, 54}, /* Row 48 */ + { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 17, 4}, { 1, 19}, { 1, 24}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 1, 18}, { 1, 54}, { 7, 46}, { 1, 56}, + { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 7, 4}, { 1, 25}, + { 1, 23}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 85}, + { 1, 51}, { 4, 40}, { 1, 51}, { 1, 41}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 1, 18}, { 1, 56}, { 6, 46}, /* Row 49 */ + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 16, 4}, + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 7, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 86}, { 1, 66}, { 1, 64}, { 4, 40}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 1, 18}, { 1, 54}, { 7, 46}, /* Row 50 */ + { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 16, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 5, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 1, 44}, { 1, 67}, { 1, 66}, { 1, 64}, { 1, 40}, { 1, 51}, { 1, 41}, + { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 56}, { 6, 46}, /* Row 51 */ + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 15, 4}, + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 3, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 5, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 2, 44}, { 1, 67}, { 1, 66}, { 1, 64}, { 1, 40}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 54}, { 7, 46}, /* Row 52 */ + { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 15, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 3, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 3, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 4, 44}, { 1, 67}, { 1, 87}, { 1, 41}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 3, 18}, { 1, 56}, { 6, 46}, /* Row 53 */ + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 14, 4}, + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 4, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 3, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 5, 44}, { 1, 88}, { 1, 89}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 3, 18}, { 1, 54}, { 7, 46}, /* Row 54 */ + { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 14, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 4, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 1, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 6, 44}, { 1, 90}, { 1, 62}, { 1, 5}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 4, 18}, { 1, 56}, { 6, 46}, /* Row 55 */ + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 13, 4}, + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 5, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 1, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 5, 44}, { 1, 33}, { 1, 91}, { 2, 4}, { 1, 5}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 4, 18}, { 1, 54}, { 7, 46}, /* Row 56 */ + { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 13, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 5, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 92}, { 1, 23}, + { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, + { 1, 93}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 5, 18}, { 1, 56}, { 6, 46}, /* Row 57 */ + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 12, 4}, + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 6, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 94}, { 1, 21}, + { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, + { 1, 34}, { 1, 62}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 5, 18}, { 1, 54}, { 7, 46}, /* Row 58 */ + { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 12, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 6, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 3, 44}, { 1, 43}, { 1, 42}, { 4, 18}, + { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, + { 2, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 19, 0}, + { 17, 0}, { 1, 95}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 6, 18}, { 1, 56}, /* Row 59 */ + { 6, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, + { 11, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 7, 18}, + { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 3, 44}, { 1, 53}, + { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, + { 5, 44}, { 1, 34}, { 1, 62}, { 3, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, + { 1, 5}, { 18, 0}, + { 16, 0}, { 1, 1}, { 1, 96}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, /* Row 60 */ + { 6, 18}, { 1, 54}, { 7, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, + { 1, 35}, { 11, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, + { 2, 18}, { 1, 21}, { 1, 47}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, + { 1, 42}, { 1, 43}, { 1, 44}, { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 7, 46}, + { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, { 5, 4}, { 1, 16}, + { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 17, 0}, + { 15, 0}, { 1, 1}, { 1, 2}, { 1, 97}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, /* Row 61 */ + { 1, 36}, { 7, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, + { 4, 44}, { 1, 34}, { 1, 62}, { 10, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, + { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 99}, { 1, 21}, { 3, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 1, 44}, { 1, 53}, { 1, 21}, + { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, + { 1, 34}, { 1, 62}, { 6, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, + { 16, 0}, + { 14, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, /* Row 62 */ + { 8, 46}, { 1, 36}, { 7, 18}, { 1, 54}, { 7, 46}, { 1, 54}, { 4, 18}, { 1, 21}, + { 1, 53}, { 5, 44}, { 1, 35}, { 10, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, + { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 100}, { 1, 42}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 101}, { 1, 42}, { 4, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, { 8, 4}, + { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 15, 0}, + { 13, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 102}, { 1, 98}, { 2, 18}, /* Row 63 */ + { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 21}, { 1, 47}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, + { 9, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 98}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, + { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 34}, { 1, 62}, { 9, 4}, { 1, 16}, + { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 14, 0}, + { 12, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 105}, { 1, 106}, /* Row 64 */ + { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 99}, { 1, 21}, + { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, + { 1, 35}, { 9, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, + { 2, 18}, { 1, 98}, { 1, 103}, { 1, 43}, { 1, 42}, { 3, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 9, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, + { 6, 44}, { 1, 35}, { 11, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, + { 13, 0}, + { 11, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 108}, /* Row 65 */ + { 1, 29}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 100}, + { 1, 42}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, + { 4, 44}, { 1, 34}, { 1, 62}, { 8, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, + { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 1, 44}, { 1, 53}, { 1, 21}, + { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 7, 18}, { 1, 54}, { 7, 46}, { 1, 56}, + { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 34}, { 1, 62}, { 12, 4}, { 1, 16}, + { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 12, 0}, + { 10, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 66 */ + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, + { 1, 103}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, { 4, 18}, + { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 8, 4}, { 1, 19}, { 1, 24}, { 2, 18}, + { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 1, 44}, { 1, 43}, + { 1, 42}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 7, 18}, { 1, 56}, { 7, 46}, + { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, { 14, 4}, { 1, 16}, + { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 11, 0}, + { 9, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 67 */ + { 1, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, + { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 7, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 2, 44}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 5, 18}, + { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 34}, + { 1, 62}, { 15, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 10, 0}, + { 8, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 68 */ + { 2, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 1, 44}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, + { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 7, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 2, 44}, { 1, 43}, { 1, 42}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 5, 18}, + { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, + { 17, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 9, 0}, + { 7, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 69 */ + { 3, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 1, 44}, { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 6, 46}, + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 6, 4}, + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, + { 1, 103}, { 3, 44}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, + { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, + { 1, 34}, { 1, 62}, { 18, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, + { 8, 0}, + { 6, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 70 */ + { 4, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 2, 44}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, + { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 6, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 3, 44}, { 1, 43}, { 1, 42}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 3, 18}, + { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, + { 20, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 7, 0}, + { 5, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 71 */ + { 5, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 2, 44}, { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 6, 46}, + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 5, 4}, + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, + { 1, 103}, { 4, 44}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, + { 1, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, + { 1, 34}, { 1, 62}, { 21, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, + { 6, 0}, + { 4, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 72 */ + { 6, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 3, 44}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, + { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 5, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 4, 44}, { 1, 43}, { 1, 42}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 1, 18}, + { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, + { 23, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 5, 0}, + { 3, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 73 */ + { 7, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 3, 44}, { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 6, 46}, + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 4, 4}, + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, + { 1, 103}, { 5, 44}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 110}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 34}, { 1, 62}, + { 24, 4}, { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 4, 0}, + { 2, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 74 */ + { 8, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 4, 44}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, + { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 4, 4}, { 1, 19}, + { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 43}, { 1, 111}, { 3, 18}, { 1, 54}, { 15, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, { 26, 4}, { 1, 16}, { 1, 14}, { 1, 7}, + { 2, 4}, { 1, 5}, { 3, 0}, + { 1, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, /* Row 75 */ + { 9, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 4, 44}, { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 6, 46}, + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 3, 4}, + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, + { 1, 103}, { 5, 44}, { 1, 32}, { 1, 83}, { 1, 21}, { 3, 18}, { 1, 56}, { 13, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 34}, { 1, 62}, { 27, 4}, + { 1, 16}, { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, { 2, 0}, + { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, { 10, 4}, /* Row 76 */ + { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, + { 1, 103}, { 5, 44}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, + { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 3, 4}, { 1, 19}, { 1, 24}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, + { 1, 33}, { 1, 112}, { 1, 23}, { 3, 18}, { 1, 54}, { 13, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, { 29, 4}, { 1, 16}, { 1, 14}, { 1, 7}, + { 2, 4}, { 1, 5}, { 1, 0}, + { 1, 2}, { 1, 6}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, { 11, 4}, { 1, 19}, /* Row 77 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 43}, { 1, 111}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 5, 18}, + { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 2, 4}, { 1, 19}, { 1, 24}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, + { 1, 33}, { 1, 7}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 56}, { 11, 46}, { 1, 56}, + { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 34}, { 1, 62}, { 30, 4}, { 1, 16}, + { 1, 14}, { 1, 7}, { 2, 4}, { 1, 5}, + { 1, 3}, { 1, 7}, { 1, 104}, { 1, 107}, { 1, 109}, { 12, 4}, { 1, 19}, { 1, 24}, /* Row 78 */ + { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, + { 1, 32}, { 1, 83}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, { 4, 18}, + { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 2, 4}, { 1, 19}, { 1, 24}, { 2, 18}, + { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 7}, { 1, 25}, { 1, 23}, { 3, 18}, { 1, 54}, { 11, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, { 32, 4}, { 1, 16}, { 1, 14}, { 1, 7}, + { 2, 4}, + { 1, 4}, { 1, 113}, { 1, 114}, { 1, 115}, { 13, 4}, { 1, 19}, { 1, 24}, { 2, 18}, /* Row 79 */ + { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 112}, { 1, 23}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 5, 18}, { 1, 42}, + { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 1, 4}, { 1, 19}, { 1, 24}, { 2, 18}, + { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 7}, { 1, 4}, { 1, 116}, { 4, 18}, { 1, 56}, { 9, 46}, { 1, 61}, { 4, 18}, + { 1, 42}, { 1, 43}, { 5, 44}, { 1, 34}, { 1, 62}, { 33, 4}, { 1, 16}, { 1, 14}, + { 1, 62}, { 1, 4}, + { 1, 4}, { 1, 7}, { 1, 117}, { 1, 8}, { 13, 4}, { 1, 19}, { 1, 24}, { 2, 18}, /* Row 80 */ + { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 7}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, { 4, 18}, + { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 1, 4}, { 1, 19}, { 1, 24}, { 2, 18}, + { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 7}, { 1, 4}, { 1, 116}, { 4, 18}, { 1, 54}, { 9, 46}, { 1, 37}, { 3, 18}, + { 1, 21}, { 1, 53}, { 6, 44}, { 1, 35}, { 35, 4}, { 1, 118}, { 1, 119}, { 1, 7}, + { 2, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 12, 4}, { 1, 19}, { 1, 24}, { 2, 18}, /* Row 81 */ + { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 7}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 5, 18}, + { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 62}, { 1, 19}, { 1, 24}, { 2, 18}, + { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 7}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 8, 46}, { 1, 60}, { 1, 21}, + { 3, 18}, { 1, 98}, { 1, 120}, { 5, 44}, { 1, 33}, { 1, 62}, { 34, 4}, { 1, 8}, + { 1, 11}, { 1, 76}, { 1, 3}, + { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 11, 4}, { 1, 19}, { 1, 24}, { 2, 18}, /* Row 82 */ + { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 7}, { 1, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, + { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 35}, { 1, 121}, { 1, 24}, { 2, 18}, + { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 7}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 10, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 53}, { 5, 44}, { 1, 33}, { 1, 62}, { 33, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 1, 4}, + { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 10, 4}, { 1, 19}, { 1, 24}, /* Row 83 */ + { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, + { 1, 33}, { 1, 7}, { 1, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 6, 46}, + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 34}, { 1, 122}, { 1, 24}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, + { 1, 33}, { 1, 112}, { 1, 23}, { 4, 18}, { 1, 56}, { 10, 46}, { 1, 56}, { 4, 18}, + { 1, 42}, { 1, 43}, { 5, 44}, { 1, 35}, { 32, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 5}, + { 1, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 9, 4}, { 1, 19}, /* Row 84 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 33}, { 1, 7}, { 2, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 123}, { 1, 24}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, + { 1, 32}, { 1, 83}, { 1, 21}, { 3, 18}, { 1, 54}, { 12, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 53}, { 5, 44}, { 1, 34}, { 1, 62}, { 30, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 1, 0}, + { 2, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 8, 4}, { 1, 19}, /* Row 85 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 33}, { 1, 7}, { 2, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 124}, { 1, 98}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, + { 1, 43}, { 1, 111}, { 4, 18}, { 1, 56}, { 12, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 5, 44}, { 1, 35}, { 29, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, + { 1, 4}, { 1, 5}, { 2, 0}, + { 3, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 7, 4}, { 1, 19}, /* Row 86 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 33}, { 1, 7}, { 3, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 4, 44}, { 1, 103}, { 1, 98}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, + { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 14, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 5, 44}, { 1, 34}, { 1, 62}, { 27, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 5}, { 3, 0}, + { 4, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 6, 4}, { 1, 19}, /* Row 87 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 33}, { 1, 7}, { 3, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 3, 44}, { 1, 103}, { 1, 98}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 4, 44}, + { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 14, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 5, 44}, { 1, 35}, { 26, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, + { 1, 4}, { 1, 5}, { 4, 0}, + { 5, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 5, 4}, { 1, 19}, /* Row 88 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 33}, { 1, 7}, { 4, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 3, 44}, { 1, 103}, { 1, 98}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 4, 44}, + { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 16, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 5, 44}, { 1, 34}, { 1, 62}, { 24, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 5}, { 5, 0}, + { 6, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 4, 4}, { 1, 19}, /* Row 89 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 33}, { 1, 7}, { 4, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 2, 44}, { 1, 103}, { 1, 98}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 3, 44}, + { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 56}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 35}, { 23, 4}, { 1, 8}, + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 6, 0}, + { 7, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 3, 4}, { 1, 19}, /* Row 90 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 33}, { 1, 7}, { 5, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 2, 44}, { 1, 103}, { 1, 98}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 3, 44}, + { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 8, 46}, { 1, 54}, { 1, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 34}, { 1, 62}, + { 21, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 7, 0}, + { 8, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 2, 4}, { 1, 19}, /* Row 91 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 33}, { 1, 7}, { 5, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 1, 44}, { 1, 103}, { 1, 98}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 2, 44}, + { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 56}, { 2, 18}, { 1, 54}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 35}, { 20, 4}, + { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 8, 0}, + { 9, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 1, 4}, { 1, 19}, /* Row 92 */ + { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, + { 5, 44}, { 1, 33}, { 1, 7}, { 6, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 4, 18}, { 1, 21}, { 1, 53}, { 1, 44}, { 1, 103}, { 1, 98}, + { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 2, 44}, + { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 8, 46}, { 1, 54}, { 3, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 34}, { 1, 62}, + { 18, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 9, 0}, + { 10, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 1, 121}, { 1, 24}, /* Row 93 */ + { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, + { 1, 33}, { 1, 7}, { 6, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 6, 46}, + { 1, 56}, { 5, 18}, { 1, 42}, { 1, 43}, { 1, 103}, { 1, 98}, { 2, 18}, { 1, 36}, + { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 1, 44}, { 1, 43}, { 1, 42}, + { 4, 18}, { 1, 56}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 54}, { 7, 46}, { 1, 56}, + { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 35}, { 17, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 10, 0}, + { 11, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 125}, { 1, 24}, { 2, 18}, /* Row 94 */ + { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, + { 1, 7}, { 7, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, + { 4, 18}, { 1, 21}, { 1, 53}, { 1, 103}, { 1, 98}, { 2, 18}, { 1, 36}, { 7, 46}, + { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 1, 44}, { 1, 53}, { 1, 21}, { 3, 18}, + { 1, 54}, { 8, 46}, { 1, 54}, { 5, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 53}, { 5, 44}, { 1, 34}, { 1, 62}, { 15, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 11, 0}, + { 12, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 126}, { 1, 98}, { 2, 18}, { 1, 36}, /* Row 95 */ + { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, { 1, 7}, + { 7, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 5, 18}, + { 1, 42}, { 1, 100}, { 1, 98}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, + { 1, 98}, { 1, 103}, { 1, 43}, { 1, 42}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 56}, + { 6, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, + { 1, 35}, { 14, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, + { 12, 0}, + { 13, 0}, { 1, 5}, { 3, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, /* Row 96 */ + { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, { 1, 7}, { 8, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, { 4, 18}, { 1, 21}, + { 1, 99}, { 1, 98}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, + { 1, 103}, { 1, 53}, { 1, 21}, { 3, 18}, { 1, 54}, { 8, 46}, { 1, 54}, { 7, 18}, + { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 34}, + { 1, 62}, { 12, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, + { 13, 0}, + { 14, 0}, { 1, 5}, { 2, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, /* Row 97 */ + { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, { 1, 7}, { 8, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 5, 18}, { 1, 47}, + { 1, 21}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 100}, + { 1, 42}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 47}, { 1, 21}, + { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, + { 1, 35}, { 11, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, + { 14, 0}, + { 15, 0}, { 1, 5}, { 1, 4}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, /* Row 98 */ + { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, { 1, 7}, { 9, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, { 8, 18}, { 1, 36}, + { 7, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 99}, { 1, 21}, { 3, 18}, { 1, 54}, + { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 127}, { 1, 42}, { 3, 18}, { 1, 56}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 34}, { 1, 62}, + { 9, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 15, 0}, + { 16, 0}, { 1, 5}, { 1, 19}, { 1, 24}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, /* Row 99 */ + { 2, 18}, { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, { 1, 7}, { 9, 4}, { 1, 25}, + { 1, 23}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 8, 18}, { 1, 36}, { 7, 46}, + { 1, 36}, { 2, 18}, { 1, 21}, { 1, 47}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 56}, + { 4, 18}, { 1, 42}, { 1, 43}, { 1, 53}, { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, { 1, 35}, { 8, 4}, { 1, 8}, + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 16, 0}, + { 17, 0}, { 1, 128}, { 1, 129}, { 2, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, /* Row 100 */ + { 1, 98}, { 1, 103}, { 5, 44}, { 1, 33}, { 1, 7}, { 10, 4}, { 1, 22}, { 1, 21}, + { 3, 18}, { 1, 54}, { 7, 46}, { 1, 54}, { 7, 18}, { 1, 36}, { 7, 46}, { 1, 36}, + { 7, 18}, { 1, 54}, { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 1, 44}, + { 1, 43}, { 1, 42}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 5, 44}, { 1, 34}, { 1, 62}, { 6, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 5}, { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 101 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 10, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 7, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 7, 18}, { 1, 56}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 2, 44}, { 1, 53}, { 1, 21}, + { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, + { 1, 35}, { 5, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, + { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 102 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 11, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 6, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 6, 18}, { 1, 54}, + { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 3, 44}, { 1, 43}, { 1, 42}, + { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, + { 1, 34}, { 1, 62}, { 3, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, + { 1, 5}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 103 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 11, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 6, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 6, 18}, { 1, 56}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 4, 44}, { 1, 53}, { 1, 21}, + { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, + { 1, 35}, { 2, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, + { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 104 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 12, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 5, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 5, 18}, { 1, 54}, + { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, { 1, 43}, { 1, 42}, + { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 5, 44}, + { 1, 34}, { 1, 62}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, + { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 105 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 12, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 5, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 5, 18}, { 1, 56}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 6, 44}, { 1, 94}, { 1, 21}, + { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 5, 44}, + { 1, 93}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 106 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 13, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 4, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 4, 18}, { 1, 54}, + { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 34}, { 1, 92}, + { 1, 23}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, + { 5, 44}, { 1, 88}, { 1, 130}, { 1, 6}, { 1, 4}, { 1, 5}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 107 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 13, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 4, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 4, 18}, { 1, 56}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 1, 4}, + { 1, 22}, { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 5, 44}, { 1, 131}, { 1, 7}, { 1, 5}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 108 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 14, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 3, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 3, 18}, { 1, 54}, + { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, + { 1, 4}, { 1, 25}, { 1, 23}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 53}, { 4, 44}, { 1, 67}, { 1, 132}, { 1, 133}, { 25, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 109 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 14, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 3, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 3, 18}, { 1, 56}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 3, 4}, + { 1, 22}, { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 2, 44}, { 1, 67}, { 1, 66}, { 1, 64}, { 1, 40}, { 25, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 110 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 15, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 54}, + { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, + { 3, 4}, { 1, 25}, { 1, 23}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 53}, { 1, 44}, { 1, 67}, { 1, 66}, { 1, 64}, { 1, 40}, { 1, 51}, + { 1, 41}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 111 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 15, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 2, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 2, 18}, { 1, 56}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 5, 4}, + { 1, 22}, { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 86}, { 1, 66}, { 1, 64}, { 4, 40}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 112 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 16, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 1, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 1, 18}, { 1, 54}, + { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, + { 5, 4}, { 1, 25}, { 1, 23}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, + { 1, 21}, { 1, 85}, { 1, 51}, { 4, 40}, { 1, 51}, { 1, 41}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 113 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 16, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 1, 18}, { 1, 36}, { 7, 46}, { 1, 36}, { 1, 18}, { 1, 56}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 7, 4}, + { 1, 22}, { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, + { 1, 48}, { 6, 40}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 114 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 17, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 54}, { 1, 36}, { 7, 46}, { 1, 36}, { 1, 54}, { 8, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 7, 4}, { 1, 25}, + { 1, 23}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 57}, + { 5, 40}, { 1, 51}, { 1, 41}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 103}, /* Row 115 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 17, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, + { 6, 46}, { 1, 56}, { 1, 36}, { 7, 46}, { 1, 36}, { 1, 56}, { 7, 46}, { 1, 56}, + { 4, 18}, { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 9, 4}, { 1, 22}, { 1, 21}, + { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, + { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 98}, { 1, 134}, /* Row 116 */ + { 5, 44}, { 1, 33}, { 1, 7}, { 18, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, + { 7, 46}, { 1, 84}, { 7, 46}, { 1, 84}, { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 9, 4}, { 1, 25}, { 1, 23}, { 3, 18}, + { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 57}, { 5, 40}, { 1, 51}, + { 1, 41}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 135}, /* Row 117 */ + { 1, 67}, { 4, 44}, { 1, 33}, { 1, 7}, { 18, 4}, { 1, 25}, { 1, 23}, { 4, 18}, + { 1, 56}, { 6, 46}, { 1, 61}, { 7, 46}, { 1, 61}, { 7, 46}, { 1, 56}, { 4, 18}, + { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 11, 4}, { 1, 22}, { 1, 21}, { 2, 18}, + { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 118 */ + { 1, 66}, { 1, 67}, { 3, 44}, { 1, 79}, { 1, 136}, { 19, 4}, { 1, 22}, { 1, 21}, + { 3, 18}, { 1, 54}, { 22, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, + { 1, 34}, { 1, 62}, { 11, 4}, { 1, 25}, { 1, 23}, { 3, 18}, { 1, 56}, { 7, 46}, + { 1, 54}, { 3, 18}, { 1, 21}, { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 119 */ + { 1, 64}, { 1, 66}, { 1, 67}, { 2, 44}, { 1, 79}, { 1, 45}, { 1, 16}, { 18, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 20, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 6, 44}, { 1, 35}, { 13, 4}, { 1, 22}, { 1, 21}, { 2, 18}, { 1, 54}, + { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 120 */ + { 1, 40}, { 1, 64}, { 1, 66}, { 1, 67}, { 1, 44}, { 1, 33}, { 1, 137}, { 1, 14}, + { 1, 16}, { 18, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 20, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 13, 4}, { 1, 138}, + { 1, 139}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 57}, + { 5, 40}, { 1, 51}, { 1, 41}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 121 */ + { 2, 40}, { 1, 64}, { 1, 66}, { 1, 67}, { 1, 33}, { 2, 7}, { 1, 14}, { 1, 16}, + { 17, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 18, 46}, { 1, 56}, { 4, 18}, + { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 13, 4}, { 1, 8}, { 1, 140}, { 1, 141}, + { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, + { 6, 40}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 122 */ + { 3, 40}, { 1, 64}, { 1, 66}, { 1, 131}, { 1, 7}, { 1, 4}, { 1, 7}, { 1, 14}, + { 1, 16}, { 17, 4}, { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 18, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 12, 4}, { 1, 8}, + { 1, 11}, { 1, 15}, { 1, 142}, { 1, 23}, { 3, 18}, { 1, 56}, { 7, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 123 */ + { 4, 40}, { 1, 64}, { 1, 143}, { 1, 144}, { 2, 4}, { 1, 7}, { 1, 14}, { 1, 16}, + { 16, 4}, { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 16, 46}, { 1, 56}, { 4, 18}, + { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 12, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 145}, { 3, 18}, { 1, 54}, { 7, 46}, { 1, 56}, { 4, 18}, + { 1, 50}, { 1, 48}, { 6, 40}, { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 124 */ + { 5, 40}, { 1, 64}, { 1, 146}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 16, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 16, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 11, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 5}, { 1, 147}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 125 */ + { 6, 40}, { 1, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 15, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 14, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 6, 44}, { 1, 35}, { 11, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, + { 1, 4}, { 1, 5}, { 2, 0}, { 1, 17}, { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 126 */ + { 6, 40}, { 2, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 15, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 14, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 10, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 5}, { 4, 0}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 16, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 127 */ + { 6, 40}, { 3, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 14, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 12, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 6, 44}, { 1, 35}, { 10, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, + { 1, 4}, { 1, 5}, { 5, 0}, { 1, 17}, { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, { 16, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 128 */ + { 6, 40}, { 4, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 14, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 12, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 9, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 5}, { 7, 0}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 57}, { 5, 40}, { 1, 51}, { 1, 41}, { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 129 */ + { 6, 40}, { 5, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 13, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 10, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 6, 44}, { 1, 35}, { 9, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, + { 1, 4}, { 1, 5}, { 8, 0}, { 1, 17}, { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 50}, { 1, 48}, { 6, 40}, { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 130 */ + { 6, 40}, { 6, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 13, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 10, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 8, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 5}, { 10, 0}, { 4, 18}, { 1, 56}, { 7, 46}, { 1, 54}, + { 3, 18}, { 1, 21}, { 1, 55}, { 5, 40}, { 1, 51}, { 1, 148}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 131 */ + { 6, 40}, { 7, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 12, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 8, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 6, 44}, { 1, 35}, { 8, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, + { 1, 4}, { 1, 5}, { 11, 0}, { 1, 17}, { 1, 21}, { 2, 18}, { 1, 54}, { 7, 46}, + { 1, 56}, { 4, 18}, { 1, 57}, { 6, 40}, { 1, 149}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 132 */ + { 6, 40}, { 8, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 12, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 54}, { 8, 46}, { 1, 54}, { 3, 18}, { 1, 21}, + { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 7, 4}, { 1, 8}, { 1, 11}, { 1, 15}, + { 1, 6}, { 1, 4}, { 1, 5}, { 13, 0}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, + { 4, 18}, { 1, 57}, { 7, 40}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 133 */ + { 6, 40}, { 9, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 11, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 56}, { 6, 46}, { 1, 56}, { 4, 18}, { 1, 42}, + { 1, 43}, { 6, 44}, { 1, 35}, { 7, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, + { 1, 4}, { 1, 5}, { 14, 0}, { 1, 17}, { 1, 21}, { 2, 18}, { 1, 54}, { 6, 46}, + { 1, 56}, { 3, 18}, { 1, 69}, { 1, 150}, { 6, 40}, { 1, 51}, { 1, 148}, { 13, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 134 */ + { 6, 40}, { 10, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 11, 4}, + { 1, 22}, { 1, 21}, { 3, 18}, { 1, 36}, { 1, 151}, { 4, 46}, { 1, 151}, { 1, 36}, + { 3, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, { 6, 4}, { 1, 8}, + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 16, 0}, { 4, 18}, { 1, 56}, + { 5, 46}, { 1, 54}, { 3, 18}, { 1, 50}, { 1, 73}, { 7, 40}, { 1, 41}, { 13, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 135 */ + { 6, 40}, { 11, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 10, 4}, + { 1, 25}, { 1, 23}, { 4, 18}, { 1, 36}, { 1, 56}, { 2, 46}, { 1, 56}, { 1, 36}, + { 4, 18}, { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 6, 4}, { 1, 8}, { 1, 11}, + { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 17, 0}, { 1, 17}, { 1, 21}, { 2, 18}, + { 1, 36}, { 1, 56}, { 2, 46}, { 1, 56}, { 1, 54}, { 3, 18}, { 1, 21}, { 1, 57}, + { 8, 40}, { 1, 41}, { 13, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 136 */ + { 6, 40}, { 12, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 10, 4}, + { 1, 22}, { 1, 21}, { 5, 18}, { 2, 36}, { 5, 18}, { 1, 21}, { 1, 53}, { 6, 44}, + { 1, 34}, { 1, 62}, { 5, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, + { 1, 5}, { 19, 0}, { 5, 18}, { 2, 36}, { 5, 18}, { 1, 50}, { 1, 48}, { 8, 40}, + { 1, 63}, { 13, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 137 */ + { 6, 40}, { 13, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 9, 4}, + { 1, 25}, { 1, 23}, { 12, 18}, { 1, 42}, { 1, 43}, { 6, 44}, { 1, 35}, { 5, 4}, + { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 20, 0}, { 1, 17}, + { 1, 21}, { 9, 18}, { 1, 47}, { 1, 70}, { 9, 40}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 36}, { 2, 18}, { 1, 47}, { 1, 73}, /* Row 138 */ + { 6, 40}, { 14, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 9, 4}, + { 1, 22}, { 1, 21}, { 10, 18}, { 1, 21}, { 1, 53}, { 6, 44}, { 1, 34}, { 1, 62}, + { 4, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 22, 0}, + { 9, 18}, { 1, 47}, { 1, 70}, { 8, 40}, { 1, 51}, { 1, 41}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 36}, { 8, 46}, { 1, 69}, { 2, 47}, { 1, 152}, { 1, 73}, /* Row 139 */ + { 6, 40}, { 15, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 8, 4}, + { 1, 19}, { 1, 27}, { 1, 21}, { 8, 18}, { 1, 21}, { 1, 153}, { 1, 103}, { 6, 44}, + { 1, 35}, { 4, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, + { 23, 0}, { 1, 147}, { 1, 154}, { 1, 18}, { 1, 21}, { 2, 18}, { 1, 21}, { 1, 47}, + { 1, 155}, { 1, 150}, { 10, 40}, { 15, 0}, + { 25, 0}, { 5, 48}, { 4, 73}, { 7, 40}, { 16, 0}, { 1, 5}, { 3, 4}, { 1, 7}, /* Row 140 */ + { 1, 14}, { 1, 16}, { 8, 4}, { 1, 19}, { 1, 22}, { 1, 23}, { 1, 21}, { 4, 18}, + { 1, 21}, { 1, 42}, { 1, 53}, { 1, 103}, { 6, 44}, { 1, 34}, { 1, 62}, { 3, 4}, + { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 27, 0}, { 1, 156}, + { 1, 17}, { 1, 157}, { 1, 55}, { 1, 48}, { 1, 64}, { 9, 40}, { 1, 51}, { 1, 41}, + { 15, 0}, + { 25, 0}, { 16, 40}, { 17, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, /* Row 141 */ + { 9, 4}, { 1, 25}, { 1, 22}, { 1, 158}, { 2, 98}, { 1, 77}, { 1, 53}, { 1, 43}, + { 7, 44}, { 1, 33}, { 1, 136}, { 3, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, + { 1, 4}, { 1, 5}, { 30, 0}, { 1, 63}, { 11, 40}, { 1, 51}, { 1, 40}, { 16, 0}, + { 25, 0}, { 16, 40}, { 18, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, /* Row 142 */ + { 10, 4}, { 1, 19}, { 1, 159}, { 1, 160}, { 1, 103}, { 7, 44}, { 1, 79}, { 1, 161}, + { 1, 136}, { 3, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, + { 32, 0}, { 1, 41}, { 1, 51}, { 8, 40}, { 1, 51}, { 1, 40}, { 17, 0}, + { 25, 0}, { 16, 40}, { 19, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, /* Row 143 */ + { 11, 4}, { 1, 62}, { 1, 35}, { 1, 34}, { 5, 33}, { 1, 161}, { 1, 136}, { 1, 7}, + { 3, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 34, 0}, + { 8, 40}, { 1, 51}, { 1, 40}, { 18, 0}, + { 25, 0}, { 16, 40}, { 20, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, /* Row 144 */ + { 12, 4}, { 7, 7}, { 4, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, + { 1, 5}, { 35, 0}, { 1, 49}, { 7, 40}, { 1, 41}, { 19, 0}, + { 25, 0}, { 16, 40}, { 21, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, /* Row 145 */ + { 21, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 64, 0}, + { 25, 0}, { 16, 40}, { 22, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, /* Row 146 */ + { 19, 4}, { 1, 8}, { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 65, 0}, + { 64, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 17, 4}, { 1, 8}, /* Row 147 */ + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 66, 0}, + { 65, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 15, 4}, { 1, 8}, /* Row 148 */ + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 67, 0}, + { 66, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 13, 4}, { 1, 8}, /* Row 149 */ + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 68, 0}, + { 67, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 11, 4}, { 1, 8}, /* Row 150 */ + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 69, 0}, + { 68, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 9, 4}, { 1, 8}, /* Row 151 */ + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 70, 0}, + { 69, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 7, 4}, { 1, 8}, /* Row 152 */ + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 71, 0}, + { 70, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 5, 4}, { 1, 8}, /* Row 153 */ + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 72, 0}, + { 71, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 3, 4}, { 1, 8}, /* Row 154 */ + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 73, 0}, + { 72, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 16}, { 1, 4}, { 1, 8}, /* Row 155 */ + { 1, 11}, { 1, 15}, { 1, 6}, { 1, 4}, { 1, 5}, { 74, 0}, + { 73, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 14}, { 1, 118}, { 1, 11}, { 1, 15}, /* Row 156 */ + { 1, 6}, { 1, 4}, { 1, 5}, { 75, 0}, + { 74, 0}, { 1, 5}, { 3, 4}, { 1, 7}, { 1, 162}, { 1, 15}, { 1, 6}, { 1, 4}, /* Row 157 */ + { 1, 5}, { 76, 0}, + { 75, 0}, { 1, 5}, { 2, 4}, { 1, 3}, { 1, 163}, { 1, 6}, { 1, 4}, { 1, 5}, /* Row 158 */ + { 77, 0}, + { 76, 0}, { 1, 5}, { 4, 4}, { 1, 5}, { 78, 0} /* Row 159 */ + }; + +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 16 + +static const struct pix_run_s g_nuttx[] = +{ + { 76, 0}, { 1, 1}, { 1, 2}, { 1, 3}, { 4, 4}, { 1, 5}, { 76, 0}, /* Row 0 */ + { 75, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 2, 8}, { 3, 4}, { 1, 5}, /* Row 1 */ + { 75, 0}, + { 74, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 10}, { 1, 11}, /* Row 2 */ + { 1, 8}, { 3, 4}, { 1, 5}, { 74, 0}, + { 73, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 3 */ + { 1, 14}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 73, 0}, + { 72, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 4 */ + { 1, 6}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 72, 0}, + { 71, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 5 */ + { 1, 6}, { 2, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 71, 0}, + { 70, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 6 */ + { 1, 6}, { 4, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 70, 0}, + { 69, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 7 */ + { 1, 6}, { 6, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 69, 0}, + { 68, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 8 */ + { 1, 6}, { 8, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 68, 0}, + { 67, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 9 */ + { 1, 6}, { 10, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 67, 0}, + { 66, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 10 */ + { 1, 6}, { 12, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 66, 0}, + { 65, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 11 */ + { 1, 6}, { 14, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 65, 0}, + { 64, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 12 */ + { 1, 6}, { 16, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 64, 0}, + { 63, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 13 */ + { 1, 6}, { 18, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 63, 0}, + { 62, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 14 */ + { 1, 6}, { 20, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 62, 0}, + { 61, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 15 */ + { 1, 6}, { 22, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 61, 0}, + { 60, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 16 */ + { 1, 6}, { 24, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 60, 0}, + { 59, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 17 */ + { 1, 6}, { 26, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 59, 0}, + { 58, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 18 */ + { 1, 6}, { 28, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 26, 0}, { 1, 17}, { 5, 18}, { 1, 17}, { 25, 0}, + { 57, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 19 */ + { 1, 6}, { 10, 4}, { 5, 19}, { 15, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, + { 3, 4}, { 1, 5}, { 23, 0}, { 1, 20}, { 9, 18}, { 1, 20}, { 23, 0}, + { 56, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, /* Row 20 */ + { 1, 6}, { 9, 4}, { 1, 19}, { 1, 21}, { 1, 22}, { 3, 23}, { 1, 22}, { 1, 21}, + { 1, 24}, { 14, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 22, 0}, { 11, 18}, { 1, 20}, { 22, 0}, + { 23, 0}, { 1, 17}, { 5, 18}, { 1, 25}, { 25, 0}, { 1, 1}, { 1, 2}, { 1, 6}, /* Row 21 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 9, 4}, { 1, 19}, { 1, 26}, + { 7, 18}, { 1, 22}, { 1, 27}, { 14, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, + { 3, 4}, { 1, 5}, { 20, 0}, { 1, 17}, { 12, 18}, { 1, 20}, { 21, 0}, + { 21, 0}, { 1, 20}, { 9, 18}, { 1, 20}, { 22, 0}, { 1, 1}, { 1, 2}, { 1, 6}, /* Row 22 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 9, 4}, { 1, 19}, { 1, 26}, + { 9, 18}, { 1, 28}, { 1, 27}, { 4, 8}, { 1, 7}, { 9, 4}, { 1, 7}, { 1, 16}, + { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 19, 0}, { 14, 18}, { 21, 0}, + { 21, 0}, { 11, 18}, { 1, 20}, { 20, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, /* Row 23 */ + { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 10, 4}, { 1, 21}, { 11, 18}, { 1, 29}, + { 1, 30}, { 2, 31}, { 1, 32}, { 1, 33}, { 1, 8}, { 9, 4}, { 1, 7}, { 1, 16}, + { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 17, 0}, { 1, 17}, { 5, 18}, { 1, 34}, + { 2, 35}, { 1, 34}, { 5, 18}, { 1, 17}, { 20, 0}, + { 20, 0}, { 1, 36}, { 12, 18}, { 1, 37}, { 4, 38}, { 1, 39}, { 13, 0}, { 1, 1}, /* Row 24 */ + { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 10, 4}, + { 1, 24}, { 1, 22}, { 4, 18}, { 3, 34}, { 5, 18}, { 1, 40}, { 1, 41}, { 3, 31}, + { 1, 42}, { 1, 8}, { 9, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, + { 1, 5}, { 16, 0}, { 5, 18}, { 1, 43}, { 4, 44}, { 1, 43}, { 4, 18}, { 1, 35}, + { 1, 45}, { 1, 46}, { 18, 0}, + { 19, 0}, { 1, 17}, { 13, 18}, { 1, 47}, { 1, 45}, { 3, 38}, { 1, 48}, { 1, 38}, /* Row 25 */ + { 11, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, + { 1, 6}, { 11, 4}, { 1, 49}, { 4, 18}, { 1, 35}, { 3, 44}, { 1, 43}, { 5, 18}, + { 1, 50}, { 4, 31}, { 1, 42}, { 1, 8}, { 9, 4}, { 1, 7}, { 1, 16}, { 1, 15}, + { 1, 8}, { 3, 4}, { 1, 5}, { 14, 0}, { 1, 17}, { 4, 18}, { 1, 34}, { 6, 44}, + { 1, 34}, { 4, 18}, { 1, 51}, { 1, 38}, { 1, 46}, { 17, 0}, + { 19, 0}, { 5, 18}, { 1, 34}, { 2, 52}, { 1, 35}, { 6, 18}, { 1, 53}, { 4, 38}, /* Row 26 */ + { 1, 48}, { 1, 39}, { 9, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 11, 4}, { 1, 3}, { 1, 54}, { 4, 18}, { 1, 55}, + { 4, 44}, { 1, 43}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 42}, { 1, 8}, + { 9, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 13, 0}, + { 5, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 4, 18}, { 1, 53}, { 2, 38}, { 1, 46}, + { 16, 0}, + { 18, 0}, { 1, 17}, { 4, 18}, { 1, 43}, { 4, 44}, { 1, 35}, { 5, 18}, { 1, 47}, /* Row 27 */ + { 1, 45}, { 5, 38}, { 8, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 12, 4}, { 1, 19}, { 1, 23}, { 3, 18}, { 1, 35}, + { 6, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 9, 4}, + { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 11, 0}, { 1, 17}, + { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 53}, { 3, 38}, { 16, 0}, + { 18, 0}, { 4, 18}, { 1, 34}, { 5, 44}, { 1, 55}, { 1, 34}, { 5, 18}, { 1, 53}, /* Row 28 */ + { 4, 38}, { 1, 48}, { 1, 39}, { 6, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, + { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 13, 4}, { 1, 19}, { 1, 23}, { 3, 18}, + { 1, 52}, { 6, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, + { 1, 56}, { 10, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, + { 10, 0}, { 5, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 51}, { 2, 38}, + { 1, 48}, { 1, 39}, { 15, 0}, + { 18, 0}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 5, 18}, { 1, 47}, { 1, 45}, /* Row 29 */ + { 5, 38}, { 5, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 14, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, + { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 10, 4}, { 1, 7}, + { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 8, 0}, { 1, 17}, { 4, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 4, 38}, { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 5, 18}, { 1, 53}, { 4, 38}, /* Row 30 */ + { 1, 48}, { 1, 39}, { 3, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 15, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, + { 8, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, + { 11, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 7, 0}, + { 5, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 53}, { 5, 38}, { 1, 1}, + { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 52}, { 5, 18}, { 1, 47}, { 1, 45}, /* Row 31 */ + { 5, 38}, { 2, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 16, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 9, 44}, + { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 11, 4}, { 1, 7}, + { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 5, 0}, { 1, 17}, { 4, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 5, 38}, { 1, 39}, + { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 9, 44}, { 1, 34}, { 5, 18}, { 1, 53}, { 4, 38}, /* Row 32 */ + { 1, 48}, { 1, 39}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 17, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 9, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 12, 4}, + { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 4, 0}, { 5, 18}, + { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 53}, { 6, 38}, { 1, 1}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 9, 44}, { 1, 52}, { 5, 18}, { 1, 47}, { 1, 45}, /* Row 33 */ + { 3, 38}, { 1, 48}, { 1, 57}, { 1, 13}, { 1, 6}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 18, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 10, 44}, + { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 12, 4}, { 1, 7}, + { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 2, 0}, { 1, 17}, { 4, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 10, 44}, { 1, 34}, { 5, 18}, { 1, 53}, { 2, 38}, /* Row 34 */ + { 1, 48}, { 1, 58}, { 1, 59}, { 1, 60}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, + { 1, 6}, { 19, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 10, 44}, { 1, 52}, + { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 13, 4}, { 1, 7}, + { 1, 16}, { 1, 15}, { 1, 8}, { 3, 4}, { 1, 5}, { 1, 0}, { 5, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 61}, { 5, 38}, { 1, 48}, { 1, 39}, { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 10, 44}, { 1, 52}, { 5, 18}, { 1, 47}, { 1, 45}, /* Row 35 */ + { 1, 48}, { 1, 58}, { 1, 59}, { 1, 31}, { 1, 32}, { 1, 62}, { 1, 12}, { 1, 13}, + { 1, 6}, { 20, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 11, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 13, 4}, { 1, 7}, { 1, 16}, + { 1, 15}, { 1, 8}, { 3, 4}, { 1, 63}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, + { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 16, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 11, 44}, { 1, 34}, { 5, 18}, { 1, 64}, { 1, 58}, /* Row 36 */ + { 1, 59}, { 3, 31}, { 1, 65}, { 1, 66}, { 1, 6}, { 21, 4}, { 1, 19}, { 1, 23}, + { 2, 18}, { 1, 34}, { 11, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, + { 1, 32}, { 1, 56}, { 14, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 1, 4}, + { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 53}, + { 5, 38}, { 1, 48}, { 1, 39}, { 16, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 11, 44}, { 1, 52}, { 5, 18}, { 1, 67}, { 1, 68}, /* Row 37 */ + { 5, 31}, { 1, 69}, { 22, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 12, 44}, + { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 14, 4}, { 1, 7}, + { 1, 16}, { 1, 15}, { 1, 8}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, + { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 12, 44}, { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, /* Row 38 */ + { 1, 70}, { 1, 7}, { 21, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 12, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 15, 4}, + { 1, 7}, { 1, 16}, { 1, 71}, { 1, 67}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 12, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, /* Row 39 */ + { 4, 31}, { 1, 32}, { 1, 56}, { 21, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, + { 13, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 16, 4}, + { 1, 72}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, + { 6, 38}, { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 13, 44}, { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, /* Row 40 */ + { 1, 33}, { 1, 7}, { 20, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 13, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 15, 4}, + { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 53}, + { 5, 38}, { 1, 48}, { 1, 39}, { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 13, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, /* Row 41 */ + { 4, 31}, { 1, 32}, { 1, 56}, { 20, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, + { 14, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 14, 4}, + { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, + { 6, 38}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 14, 44}, { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, /* Row 42 */ + { 1, 33}, { 1, 7}, { 19, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 14, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 13, 4}, + { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 53}, + { 5, 38}, { 1, 48}, { 1, 39}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 14, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, /* Row 43 */ + { 4, 31}, { 1, 32}, { 1, 56}, { 19, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 73}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, + { 1, 7}, { 12, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, + { 1, 47}, { 1, 45}, { 6, 38}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 15, 44}, { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, /* Row 44 */ + { 1, 33}, { 1, 7}, { 18, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, + { 1, 56}, { 11, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 73}, { 6, 44}, { 1, 52}, { 5, 18}, /* Row 45 */ + { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 18, 4}, { 1, 19}, { 1, 23}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, + { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 10, 4}, { 1, 21}, { 4, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, /* Row 46 */ + { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 17, 4}, { 1, 19}, { 1, 23}, { 2, 18}, + { 1, 34}, { 7, 44}, { 2, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, + { 4, 31}, { 1, 32}, { 1, 56}, { 9, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 1, 52}, { 6, 44}, { 1, 52}, /* Row 47 */ + { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 17, 4}, { 1, 19}, + { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 1, 18}, { 1, 52}, { 7, 44}, + { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 8, 4}, { 1, 21}, + { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, + { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 2, 34}, { 7, 44}, { 1, 34}, { 5, 18}, /* Row 48 */ + { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 16, 4}, { 1, 19}, { 1, 23}, { 2, 18}, + { 1, 34}, { 7, 44}, { 1, 34}, { 1, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 7, 4}, { 1, 24}, { 1, 22}, + { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 74}, { 1, 48}, { 4, 38}, + { 1, 48}, { 1, 39}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 1, 18}, { 1, 52}, { 6, 44}, /* Row 49 */ + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 16, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 6, 4}, + { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 75}, + { 1, 58}, { 1, 48}, { 4, 38}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 1, 18}, { 1, 34}, { 7, 44}, /* Row 50 */ + { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 15, 4}, { 1, 19}, + { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 34}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 5, 4}, + { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 1, 31}, { 1, 59}, { 1, 58}, { 1, 48}, { 1, 38}, { 1, 48}, { 1, 39}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 52}, { 6, 44}, /* Row 51 */ + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 15, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 3, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 4, 4}, + { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, + { 2, 31}, { 1, 59}, { 1, 58}, { 1, 48}, { 1, 38}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 34}, { 7, 44}, /* Row 52 */ + { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 14, 4}, { 1, 19}, + { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 3, 18}, { 1, 34}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 3, 4}, + { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 4, 31}, { 1, 59}, { 1, 76}, { 1, 39}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 3, 18}, { 1, 52}, { 6, 44}, /* Row 53 */ + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 14, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 2, 4}, + { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, + { 5, 31}, { 1, 77}, { 1, 78}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 3, 18}, { 1, 34}, { 7, 44}, /* Row 54 */ + { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 13, 4}, { 1, 19}, + { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 34}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 1, 4}, + { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 6, 31}, { 1, 32}, { 1, 56}, { 1, 5}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 4, 18}, { 1, 52}, { 6, 44}, /* Row 55 */ + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 13, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 4}, { 1, 21}, + { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 6, 31}, + { 1, 79}, { 1, 7}, { 1, 4}, { 1, 5}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 4, 18}, { 1, 34}, { 7, 44}, /* Row 56 */ + { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 12, 4}, { 1, 19}, + { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 34}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 80}, { 1, 22}, + { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 81}, + { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 5, 18}, { 1, 52}, { 6, 44}, /* Row 57 */ + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 12, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 6, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 82}, { 4, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 32}, { 1, 56}, + { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 5, 18}, { 1, 34}, { 7, 44}, /* Row 58 */ + { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 11, 4}, { 1, 19}, + { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 6, 18}, { 1, 34}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 3, 31}, { 1, 41}, { 1, 40}, { 4, 18}, + { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, { 2, 7}, + { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 19, 0}, + { 17, 0}, { 1, 83}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 6, 18}, { 1, 52}, /* Row 59 */ + { 6, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, + { 11, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 7, 18}, + { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 3, 31}, { 1, 50}, { 4, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 32}, + { 1, 56}, { 2, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, + { 18, 0}, + { 16, 0}, { 1, 1}, { 1, 84}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, /* Row 60 */ + { 6, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, + { 1, 7}, { 10, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 3, 18}, { 1, 85}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, + { 1, 41}, { 1, 31}, { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, { 1, 7}, { 3, 4}, { 1, 7}, { 1, 16}, + { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 17, 0}, + { 15, 0}, { 1, 1}, { 1, 2}, { 1, 86}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, /* Row 61 */ + { 1, 34}, { 7, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, + { 4, 31}, { 1, 32}, { 1, 56}, { 10, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 87}, { 4, 18}, { 1, 52}, { 7, 44}, + { 1, 34}, { 4, 18}, { 1, 50}, { 1, 88}, { 1, 50}, { 4, 18}, { 1, 34}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 32}, { 1, 56}, { 5, 4}, + { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 16, 0}, + { 14, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 89}, { 1, 23}, { 2, 18}, { 1, 34}, /* Row 62 */ + { 8, 44}, { 1, 34}, { 7, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 50}, + { 5, 31}, { 1, 33}, { 1, 7}, { 9, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 90}, { 1, 40}, { 3, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 91}, { 1, 40}, { 4, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, { 1, 7}, { 6, 4}, + { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 15, 0}, + { 13, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 71}, { 1, 29}, { 2, 18}, /* Row 63 */ + { 1, 34}, { 8, 44}, { 1, 34}, { 3, 18}, { 1, 85}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 9, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 1, 50}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 29}, + { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, + { 1, 32}, { 1, 56}, { 8, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, + { 1, 5}, { 14, 0}, + { 12, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 94}, { 1, 95}, /* Row 64 */ + { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 87}, { 4, 18}, + { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, + { 8, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 1, 41}, { 1, 40}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, + { 9, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, + { 1, 7}, { 9, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, + { 13, 0}, + { 11, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 97}, /* Row 65 */ + { 1, 28}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 90}, + { 1, 40}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, + { 4, 31}, { 1, 32}, { 1, 56}, { 8, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 1, 31}, { 1, 50}, { 4, 18}, + { 1, 52}, { 7, 44}, { 1, 34}, { 7, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 5, 31}, { 1, 32}, { 1, 56}, { 11, 4}, { 1, 7}, { 1, 16}, + { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 12, 0}, + { 10, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 66 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 1, 50}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 50}, + { 5, 31}, { 1, 33}, { 1, 7}, { 7, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 1, 31}, { 1, 41}, { 1, 40}, + { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 7, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, { 1, 7}, { 12, 4}, { 1, 7}, { 1, 16}, + { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 11, 0}, + { 9, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 67 */ + { 1, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, + { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 7, 4}, { 1, 19}, + { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, + { 2, 31}, { 1, 50}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 32}, { 1, 56}, + { 14, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 10, 0}, + { 8, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 68 */ + { 2, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 1, 31}, { 1, 50}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 6, 4}, { 1, 19}, { 1, 23}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 2, 31}, + { 1, 41}, { 1, 40}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 5, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, { 1, 7}, { 15, 4}, + { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 9, 0}, + { 7, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 69 */ + { 3, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 1, 31}, { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 6, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 3, 31}, { 1, 50}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 3, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 32}, + { 1, 56}, { 17, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, + { 8, 0}, + { 6, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 70 */ + { 4, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 2, 31}, { 1, 50}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 5, 4}, { 1, 19}, { 1, 23}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 3, 31}, + { 1, 41}, { 1, 40}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 3, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, { 1, 7}, { 18, 4}, + { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 7, 0}, + { 5, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 71 */ + { 5, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 2, 31}, { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 5, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 4, 31}, { 1, 50}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 1, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 32}, + { 1, 56}, { 20, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, + { 6, 0}, + { 4, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 72 */ + { 6, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 3, 31}, { 1, 50}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 4, 4}, { 1, 19}, { 1, 23}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 4, 31}, + { 1, 41}, { 1, 40}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 1, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, { 1, 7}, { 21, 4}, + { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 5, 0}, + { 3, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 73 */ + { 7, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 3, 31}, { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 4, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 5, 31}, { 1, 50}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 99}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 32}, { 1, 56}, { 23, 4}, + { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 4, 0}, + { 2, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 74 */ + { 8, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 4, 31}, { 1, 50}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 5, 18}, { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 3, 4}, { 1, 19}, { 1, 23}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 5, 31}, + { 1, 41}, { 1, 67}, { 3, 18}, { 1, 34}, { 15, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 6, 31}, { 1, 33}, { 1, 7}, { 24, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, + { 2, 4}, { 1, 5}, { 3, 0}, + { 1, 0}, { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, /* Row 75 */ + { 9, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, + { 1, 29}, { 1, 92}, { 4, 31}, { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 3, 4}, + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 6, 31}, { 1, 72}, { 4, 18}, { 1, 52}, { 13, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 5, 31}, { 1, 32}, { 1, 56}, { 26, 4}, { 1, 7}, { 1, 16}, + { 1, 15}, { 1, 8}, { 2, 4}, { 1, 5}, { 2, 0}, + { 1, 1}, { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, { 10, 4}, /* Row 76 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 5, 31}, { 1, 50}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, + { 1, 50}, { 5, 31}, { 1, 33}, { 1, 7}, { 2, 4}, { 1, 19}, { 1, 23}, { 2, 18}, + { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 80}, + { 1, 22}, { 3, 18}, { 1, 34}, { 13, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, + { 1, 33}, { 1, 7}, { 27, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, + { 1, 5}, { 1, 0}, + { 1, 2}, { 1, 6}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, { 11, 4}, { 1, 19}, /* Row 77 */ + { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, + { 5, 31}, { 1, 41}, { 1, 67}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 5, 18}, + { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 2, 4}, { 1, 19}, { 1, 23}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, + { 1, 8}, { 1, 21}, { 4, 18}, { 1, 52}, { 11, 44}, { 1, 52}, { 4, 18}, { 1, 40}, + { 1, 41}, { 5, 31}, { 1, 32}, { 1, 56}, { 29, 4}, { 1, 7}, { 1, 16}, { 1, 15}, + { 1, 8}, { 2, 4}, { 1, 5}, + { 1, 3}, { 1, 8}, { 1, 93}, { 1, 96}, { 1, 98}, { 12, 4}, { 1, 19}, { 1, 23}, /* Row 78 */ + { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, + { 1, 72}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, + { 1, 33}, { 1, 7}, { 1, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 1, 24}, { 1, 22}, + { 3, 18}, { 1, 34}, { 11, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, + { 1, 7}, { 30, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 8}, { 2, 4}, + { 1, 4}, { 1, 33}, { 1, 100}, { 1, 98}, { 13, 4}, { 1, 19}, { 1, 23}, { 2, 18}, /* Row 79 */ + { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 80}, + { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, + { 4, 31}, { 1, 32}, { 1, 56}, { 1, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 1, 4}, + { 1, 101}, { 4, 18}, { 1, 52}, { 9, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, + { 5, 31}, { 1, 32}, { 1, 56}, { 32, 4}, { 1, 7}, { 1, 16}, { 1, 15}, { 1, 56}, + { 1, 7}, + { 1, 4}, { 1, 8}, { 1, 102}, { 1, 9}, { 1, 7}, { 12, 4}, { 1, 19}, { 1, 23}, /* Row 80 */ + { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, + { 1, 8}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 50}, + { 5, 31}, { 1, 33}, { 1, 7}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 1, 4}, { 1, 101}, + { 4, 18}, { 1, 34}, { 9, 44}, { 1, 35}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 33}, + { 1, 7}, { 33, 4}, { 1, 7}, { 1, 103}, { 1, 10}, { 1, 8}, + { 2, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 11, 4}, { 1, 19}, { 1, 23}, /* Row 81 */ + { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, + { 1, 8}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 5, 18}, + { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 56}, { 1, 19}, { 1, 23}, { 2, 18}, + { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, + { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 8, 44}, { 1, 104}, { 4, 18}, { 1, 29}, + { 1, 68}, { 6, 31}, { 1, 56}, { 33, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 66}, + { 1, 3}, + { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 10, 4}, { 1, 19}, { 1, 23}, /* Row 82 */ + { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, + { 1, 8}, { 1, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, + { 1, 50}, { 5, 31}, { 1, 33}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 1, 21}, { 4, 18}, + { 1, 34}, { 10, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 56}, { 32, 4}, + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, + { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 9, 4}, { 1, 19}, /* Row 83 */ + { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, + { 6, 31}, { 1, 8}, { 1, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 32}, { 1, 105}, { 1, 23}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, + { 1, 80}, { 1, 22}, { 4, 18}, { 1, 52}, { 10, 44}, { 1, 52}, { 4, 18}, { 1, 40}, + { 1, 41}, { 5, 31}, { 1, 33}, { 1, 7}, { 30, 4}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, + { 1, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 8, 4}, /* Row 84 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 6, 31}, { 1, 8}, { 2, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 5, 18}, { 1, 50}, { 5, 31}, { 1, 106}, { 1, 23}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 72}, { 4, 18}, + { 1, 34}, { 12, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 32}, { 1, 56}, + { 29, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, + { 1, 0}, + { 2, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 7, 4}, /* Row 85 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 6, 31}, { 1, 8}, { 2, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, + { 6, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 107}, { 1, 29}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 5, 31}, + { 1, 41}, { 1, 67}, { 4, 18}, { 1, 52}, { 12, 44}, { 1, 52}, { 4, 18}, { 1, 40}, + { 1, 41}, { 5, 31}, { 1, 33}, { 1, 7}, { 27, 4}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 2, 0}, + { 3, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 6, 4}, /* Row 86 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 6, 31}, { 1, 8}, { 3, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 5, 18}, { 1, 50}, { 4, 31}, { 1, 92}, { 1, 29}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 5, 31}, { 1, 50}, { 4, 18}, + { 1, 34}, { 14, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 32}, { 1, 56}, + { 26, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, + { 3, 0}, + { 4, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 5, 4}, /* Row 87 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 6, 31}, { 1, 8}, { 3, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, + { 6, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 3, 31}, { 1, 92}, { 1, 29}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 4, 31}, + { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 14, 44}, { 1, 52}, { 4, 18}, { 1, 40}, + { 1, 41}, { 5, 31}, { 1, 33}, { 1, 7}, { 24, 4}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 4, 0}, + { 5, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 4, 4}, /* Row 88 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 6, 31}, { 1, 8}, { 4, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 5, 18}, { 1, 50}, { 3, 31}, { 1, 92}, { 1, 29}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 4, 31}, { 1, 50}, { 4, 18}, + { 1, 34}, { 16, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 32}, { 1, 56}, + { 23, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, + { 5, 0}, + { 6, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 3, 4}, /* Row 89 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 6, 31}, { 1, 8}, { 4, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, + { 6, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 2, 31}, { 1, 92}, { 1, 29}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 3, 31}, + { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 52}, { 1, 34}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 33}, { 1, 7}, { 21, 4}, + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 6, 0}, + { 7, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 2, 4}, /* Row 90 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 6, 31}, { 1, 8}, { 5, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 5, 18}, { 1, 50}, { 2, 31}, { 1, 92}, { 1, 29}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 3, 31}, { 1, 50}, { 4, 18}, + { 1, 34}, { 8, 44}, { 1, 34}, { 1, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, + { 1, 50}, { 5, 31}, { 1, 32}, { 1, 56}, { 20, 4}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 7, 0}, + { 8, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 1, 4}, /* Row 91 */ + { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 6, 31}, { 1, 8}, { 5, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, + { 6, 44}, { 1, 52}, { 5, 18}, { 1, 40}, { 1, 41}, { 1, 31}, { 1, 92}, { 1, 29}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 2, 31}, + { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 52}, { 2, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 33}, { 1, 7}, + { 18, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, + { 8, 0}, + { 9, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 1, 19}, /* Row 92 */ + { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, + { 6, 31}, { 1, 8}, { 6, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 5, 18}, { 1, 50}, { 1, 31}, { 1, 92}, { 1, 29}, { 2, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 2, 31}, { 1, 50}, { 4, 18}, { 1, 34}, + { 8, 44}, { 1, 34}, { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 5, 31}, { 1, 32}, { 1, 56}, { 17, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, + { 1, 6}, { 1, 4}, { 1, 5}, { 9, 0}, + { 10, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 19}, { 1, 23}, /* Row 93 */ + { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, + { 1, 8}, { 6, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, + { 5, 18}, { 1, 40}, { 1, 41}, { 1, 92}, { 1, 29}, { 2, 18}, { 1, 34}, { 7, 44}, + { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 1, 31}, { 1, 41}, { 1, 40}, { 4, 18}, + { 1, 52}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 5, 31}, { 1, 33}, { 1, 7}, { 15, 4}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 10, 0}, + { 11, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 108}, { 1, 23}, { 2, 18}, /* Row 94 */ + { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, + { 7, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 50}, + { 1, 92}, { 1, 29}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 1, 31}, { 1, 50}, { 4, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 5, 18}, + { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 32}, { 1, 56}, + { 14, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, + { 11, 0}, + { 12, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 109}, { 1, 29}, { 2, 18}, { 1, 34}, /* Row 95 */ + { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 7, 4}, + { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 5, 18}, { 1, 40}, + { 1, 90}, { 1, 29}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, + { 1, 92}, { 1, 41}, { 1, 40}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 52}, { 6, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 33}, + { 1, 7}, { 12, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, + { 1, 5}, { 12, 0}, + { 13, 0}, { 1, 5}, { 3, 4}, { 1, 89}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, /* Row 96 */ + { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 8, 4}, { 1, 21}, + { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 87}, { 1, 29}, { 2, 18}, + { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 1, 50}, { 4, 18}, + { 1, 34}, { 8, 44}, { 1, 34}, { 7, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, + { 1, 50}, { 5, 31}, { 1, 32}, { 1, 56}, { 11, 4}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 13, 0}, + { 14, 0}, { 1, 5}, { 2, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, /* Row 97 */ + { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 8, 4}, { 1, 24}, + { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 5, 18}, { 1, 85}, { 3, 18}, + { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 90}, { 1, 40}, { 4, 18}, + { 1, 52}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 85}, { 3, 18}, { 1, 34}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 33}, { 1, 7}, { 9, 4}, + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 14, 0}, + { 15, 0}, { 1, 5}, { 1, 4}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, /* Row 98 */ + { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 9, 4}, { 1, 21}, + { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 8, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 2, 18}, { 1, 29}, { 1, 87}, { 4, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 4, 18}, + { 1, 87}, { 1, 40}, { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 5, 31}, { 1, 32}, { 1, 56}, { 8, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, + { 1, 6}, { 1, 4}, { 1, 5}, { 15, 0}, + { 16, 0}, { 1, 5}, { 1, 19}, { 1, 23}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, /* Row 99 */ + { 2, 18}, { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 9, 4}, { 1, 24}, { 1, 22}, + { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 8, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 3, 18}, { 1, 85}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, + { 1, 41}, { 1, 50}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, + { 1, 41}, { 5, 31}, { 1, 33}, { 1, 7}, { 6, 4}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 16, 0}, + { 17, 0}, { 1, 110}, { 1, 111}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, /* Row 100 */ + { 1, 29}, { 1, 92}, { 6, 31}, { 1, 8}, { 10, 4}, { 1, 21}, { 4, 18}, { 1, 34}, + { 7, 44}, { 1, 34}, { 7, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 7, 18}, { 1, 34}, + { 8, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 1, 31}, { 1, 41}, { 1, 40}, { 3, 18}, + { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 32}, { 1, 56}, + { 5, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, + { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 101 */ + { 6, 31}, { 1, 8}, { 10, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 7, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 7, 18}, { 1, 52}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 2, 31}, { 1, 50}, { 3, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 33}, { 1, 7}, + { 3, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, + { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 102 */ + { 6, 31}, { 1, 8}, { 11, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 6, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 6, 18}, { 1, 34}, { 8, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 3, 31}, { 1, 41}, { 1, 40}, { 3, 18}, { 1, 52}, { 7, 44}, + { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 32}, { 1, 56}, { 2, 4}, { 1, 7}, + { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 103 */ + { 6, 31}, { 1, 8}, { 11, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 6, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 6, 18}, { 1, 52}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 4, 31}, { 1, 50}, { 3, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 33}, { 2, 7}, + { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 104 */ + { 6, 31}, { 1, 8}, { 12, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 5, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 34}, { 8, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 5, 31}, { 1, 41}, { 1, 40}, { 3, 18}, { 1, 52}, { 7, 44}, + { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 32}, { 1, 56}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 105 */ + { 6, 31}, { 1, 8}, { 12, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 5, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 5, 18}, { 1, 52}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 6, 31}, { 1, 82}, { 3, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, { 1, 81}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 106 */ + { 6, 31}, { 1, 8}, { 13, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 34}, { 8, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 6, 31}, { 1, 32}, { 1, 80}, { 1, 22}, { 3, 18}, { 1, 52}, + { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 5, 31}, { 1, 77}, { 1, 112}, { 1, 6}, + { 1, 4}, { 1, 5}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 107 */ + { 6, 31}, { 1, 8}, { 13, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 52}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 4}, { 1, 21}, + { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 5, 31}, + { 1, 113}, { 1, 8}, { 1, 5}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 108 */ + { 6, 31}, { 1, 8}, { 14, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 3, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 6, 31}, { 1, 32}, { 1, 56}, { 1, 4}, { 1, 24}, { 1, 22}, + { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 4, 31}, { 1, 59}, + { 1, 58}, { 1, 114}, { 25, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 109 */ + { 6, 31}, { 1, 8}, { 14, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 3, 18}, { 1, 52}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 2, 4}, + { 1, 21}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, + { 2, 31}, { 1, 59}, { 1, 58}, { 1, 48}, { 1, 38}, { 25, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 110 */ + { 6, 31}, { 1, 8}, { 15, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 34}, { 8, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 6, 31}, { 1, 32}, { 1, 56}, { 3, 4}, { 1, 24}, { 1, 22}, + { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 1, 31}, { 1, 59}, + { 1, 58}, { 1, 48}, { 1, 38}, { 1, 48}, { 1, 39}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 111 */ + { 6, 31}, { 1, 8}, { 15, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 2, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 2, 18}, { 1, 52}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 4, 4}, + { 1, 21}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, { 1, 75}, + { 1, 58}, { 1, 48}, { 4, 38}, { 24, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 112 */ + { 6, 31}, { 1, 8}, { 16, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 1, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 1, 18}, { 1, 34}, { 8, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 6, 31}, { 1, 32}, { 1, 56}, { 5, 4}, { 1, 24}, { 1, 22}, + { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 74}, { 1, 48}, { 4, 38}, + { 1, 48}, { 1, 39}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 113 */ + { 6, 31}, { 1, 8}, { 16, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 1, 18}, { 1, 34}, { 7, 44}, { 1, 34}, { 1, 18}, { 1, 52}, { 7, 44}, + { 1, 52}, { 4, 18}, { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 6, 4}, + { 1, 21}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, + { 6, 38}, { 23, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 114 */ + { 6, 31}, { 1, 8}, { 17, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 2, 34}, + { 7, 44}, { 2, 34}, { 8, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 32}, + { 1, 56}, { 7, 4}, { 1, 24}, { 1, 22}, { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 92}, /* Row 115 */ + { 6, 31}, { 1, 8}, { 17, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, + { 1, 52}, { 1, 34}, { 7, 44}, { 1, 34}, { 1, 52}, { 7, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 8, 4}, { 1, 21}, { 3, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 22, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 29}, { 1, 115}, /* Row 116 */ + { 6, 31}, { 1, 8}, { 18, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 7, 44}, { 1, 34}, + { 7, 44}, { 1, 34}, { 8, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 32}, + { 1, 56}, { 9, 4}, { 1, 24}, { 1, 22}, { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 116}, /* Row 117 */ + { 1, 59}, { 5, 31}, { 1, 8}, { 18, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, + { 6, 44}, { 1, 73}, { 7, 44}, { 1, 73}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 40}, + { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 10, 4}, { 1, 21}, { 3, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 21, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 118 */ + { 1, 58}, { 1, 59}, { 4, 31}, { 1, 16}, { 1, 7}, { 18, 4}, { 1, 21}, { 4, 18}, + { 1, 34}, { 22, 44}, { 1, 34}, { 4, 18}, { 1, 50}, { 6, 31}, { 1, 32}, { 1, 56}, + { 11, 4}, { 1, 24}, { 1, 22}, { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, + { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 119 */ + { 1, 48}, { 1, 58}, { 1, 59}, { 3, 31}, { 1, 42}, { 1, 16}, { 1, 7}, { 17, 4}, + { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 20, 44}, { 1, 52}, { 4, 18}, { 1, 40}, + { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 12, 4}, { 1, 21}, { 3, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 20, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 120 */ + { 1, 38}, { 1, 48}, { 1, 58}, { 1, 59}, { 2, 31}, { 1, 56}, { 1, 15}, { 1, 16}, + { 1, 7}, { 17, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 20, 44}, { 1, 34}, { 4, 18}, + { 1, 50}, { 6, 31}, { 1, 32}, { 1, 56}, { 12, 4}, { 1, 7}, { 1, 117}, { 1, 73}, + { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, + { 1, 39}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 121 */ + { 2, 38}, { 1, 48}, { 1, 58}, { 1, 59}, { 1, 31}, { 2, 8}, { 1, 15}, { 1, 16}, + { 1, 7}, { 16, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 18, 44}, { 1, 52}, + { 4, 18}, { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 11, 4}, { 1, 7}, + { 1, 9}, { 1, 118}, { 1, 119}, { 3, 18}, { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, + { 1, 47}, { 1, 45}, { 6, 38}, { 19, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 122 */ + { 3, 38}, { 1, 48}, { 1, 58}, { 1, 113}, { 1, 8}, { 1, 4}, { 1, 8}, { 1, 15}, + { 1, 16}, { 1, 7}, { 16, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 18, 44}, { 1, 34}, + { 4, 18}, { 1, 50}, { 6, 31}, { 1, 32}, { 1, 56}, { 11, 4}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 120}, { 1, 22}, { 3, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 123 */ + { 4, 38}, { 1, 48}, { 1, 121}, { 1, 122}, { 2, 4}, { 1, 8}, { 1, 15}, { 1, 16}, + { 1, 7}, { 15, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 16, 44}, { 1, 52}, + { 4, 18}, { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 10, 4}, { 1, 7}, + { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 123}, { 3, 18}, { 1, 34}, + { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 18, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 124 */ + { 5, 38}, { 1, 48}, { 1, 124}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 15, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 16, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 6, 31}, { 1, 32}, { 1, 56}, { 10, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, + { 1, 6}, { 1, 4}, { 1, 5}, { 1, 125}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 125 */ + { 6, 38}, { 1, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 14, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 14, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 9, 4}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 2, 0}, { 1, 17}, { 3, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 17, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 126 */ + { 6, 38}, { 2, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 14, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 14, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 6, 31}, { 1, 32}, { 1, 56}, { 9, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, + { 1, 6}, { 1, 4}, { 1, 5}, { 4, 0}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 16, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 127 */ + { 6, 38}, { 3, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 13, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 12, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 8, 4}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 5, 0}, { 1, 17}, { 3, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 16, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 128 */ + { 6, 38}, { 4, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 13, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 12, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 6, 31}, { 1, 32}, { 1, 56}, { 8, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, + { 1, 6}, { 1, 4}, { 1, 5}, { 7, 0}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 53}, { 5, 38}, { 1, 48}, { 1, 39}, { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 129 */ + { 6, 38}, { 5, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 12, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 10, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 7, 4}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 8, 0}, { 1, 17}, { 3, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 47}, { 1, 45}, { 6, 38}, { 15, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 130 */ + { 6, 38}, { 6, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 12, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 10, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 6, 31}, { 1, 32}, { 1, 56}, { 7, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, + { 1, 6}, { 1, 4}, { 1, 5}, { 10, 0}, { 4, 18}, { 1, 52}, { 7, 44}, { 1, 34}, + { 4, 18}, { 1, 51}, { 5, 38}, { 1, 48}, { 1, 126}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 131 */ + { 6, 38}, { 7, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 11, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 8, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 6, 4}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 11, 0}, { 1, 17}, { 3, 18}, + { 1, 34}, { 7, 44}, { 1, 52}, { 4, 18}, { 1, 53}, { 6, 38}, { 1, 127}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 132 */ + { 6, 38}, { 8, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 11, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 4, 18}, { 1, 50}, + { 6, 31}, { 1, 32}, { 1, 56}, { 6, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, + { 1, 6}, { 1, 4}, { 1, 5}, { 13, 0}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, + { 4, 18}, { 1, 53}, { 7, 38}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 133 */ + { 6, 38}, { 9, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 10, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 52}, { 6, 44}, { 1, 52}, { 4, 18}, + { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 5, 4}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 14, 0}, { 1, 17}, { 3, 18}, + { 1, 34}, { 6, 44}, { 1, 52}, { 4, 18}, { 1, 128}, { 6, 38}, { 1, 48}, { 1, 126}, + { 13, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 134 */ + { 6, 38}, { 10, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 10, 4}, { 1, 21}, { 4, 18}, { 1, 34}, { 1, 55}, { 4, 44}, { 1, 55}, { 1, 34}, + { 4, 18}, { 1, 50}, { 6, 31}, { 1, 32}, { 1, 56}, { 5, 4}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 16, 0}, { 4, 18}, { 1, 52}, + { 5, 44}, { 1, 34}, { 3, 18}, { 1, 47}, { 1, 45}, { 7, 38}, { 1, 39}, { 13, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 135 */ + { 6, 38}, { 11, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 9, 4}, { 1, 24}, { 1, 22}, { 4, 18}, { 1, 34}, { 1, 52}, { 2, 44}, { 1, 52}, + { 1, 34}, { 4, 18}, { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, { 1, 7}, { 4, 4}, + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 17, 0}, + { 1, 17}, { 3, 18}, { 1, 34}, { 1, 52}, { 2, 44}, { 1, 52}, { 1, 34}, { 4, 18}, + { 1, 53}, { 8, 38}, { 1, 39}, { 13, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 136 */ + { 6, 38}, { 12, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 9, 4}, { 1, 21}, { 6, 18}, { 2, 34}, { 6, 18}, { 1, 50}, { 6, 31}, { 1, 32}, + { 1, 56}, { 4, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, + { 1, 5}, { 19, 0}, { 5, 18}, { 2, 34}, { 5, 18}, { 1, 47}, { 1, 45}, { 8, 38}, + { 1, 1}, { 13, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 137 */ + { 6, 38}, { 13, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 8, 4}, { 1, 24}, { 1, 22}, { 12, 18}, { 1, 40}, { 1, 41}, { 6, 31}, { 1, 33}, + { 1, 7}, { 3, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, + { 1, 5}, { 20, 0}, { 1, 17}, { 10, 18}, { 1, 35}, { 1, 61}, { 9, 38}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 34}, { 2, 18}, { 1, 35}, { 1, 45}, /* Row 138 */ + { 6, 38}, { 14, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 8, 4}, { 1, 21}, { 12, 18}, { 1, 50}, { 6, 31}, { 1, 32}, { 1, 56}, { 3, 4}, + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 22, 0}, + { 9, 18}, { 1, 35}, { 1, 61}, { 8, 38}, { 1, 48}, { 1, 39}, { 14, 0}, + { 18, 0}, { 3, 18}, { 1, 34}, { 8, 44}, { 1, 18}, { 2, 35}, { 1, 129}, { 1, 45}, /* Row 139 */ + { 6, 38}, { 15, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, + { 7, 4}, { 1, 19}, { 1, 26}, { 10, 18}, { 1, 130}, { 1, 107}, { 6, 31}, { 1, 33}, + { 1, 7}, { 2, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, + { 1, 5}, { 23, 0}, { 1, 131}, { 1, 132}, { 5, 18}, { 1, 35}, { 1, 133}, { 1, 128}, + { 10, 38}, { 15, 0}, + { 25, 0}, { 9, 45}, { 7, 38}, { 16, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, /* Row 140 */ + { 1, 16}, { 1, 7}, { 7, 4}, { 1, 19}, { 1, 21}, { 1, 22}, { 6, 18}, { 1, 40}, + { 1, 50}, { 1, 107}, { 6, 31}, { 1, 32}, { 1, 56}, { 2, 4}, { 1, 7}, { 1, 9}, + { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 27, 0}, { 1, 134}, { 1, 17}, + { 1, 135}, { 1, 51}, { 1, 45}, { 1, 136}, { 9, 38}, { 1, 48}, { 1, 39}, { 15, 0}, + { 25, 0}, { 16, 38}, { 17, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, /* Row 141 */ + { 1, 7}, { 8, 4}, { 1, 24}, { 1, 21}, { 1, 22}, { 2, 29}, { 1, 67}, { 1, 50}, + { 1, 41}, { 8, 31}, { 1, 16}, { 1, 7}, { 1, 4}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 30, 0}, { 1, 1}, { 11, 38}, { 1, 48}, + { 1, 38}, { 16, 0}, + { 25, 0}, { 16, 38}, { 18, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, /* Row 142 */ + { 1, 7}, { 9, 4}, { 1, 89}, { 1, 137}, { 1, 138}, { 1, 92}, { 8, 31}, { 1, 42}, + { 1, 16}, { 1, 7}, { 1, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, + { 1, 4}, { 1, 5}, { 32, 0}, { 1, 39}, { 1, 48}, { 8, 38}, { 1, 48}, { 1, 38}, + { 17, 0}, + { 25, 0}, { 16, 38}, { 19, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, /* Row 143 */ + { 1, 7}, { 9, 4}, { 1, 7}, { 1, 56}, { 1, 33}, { 1, 32}, { 5, 31}, { 1, 42}, + { 1, 16}, { 1, 8}, { 2, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, + { 1, 4}, { 1, 5}, { 34, 0}, { 8, 38}, { 1, 48}, { 1, 38}, { 18, 0}, + { 25, 0}, { 16, 38}, { 20, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, /* Row 144 */ + { 1, 7}, { 10, 4}, { 1, 7}, { 7, 8}, { 3, 4}, { 1, 7}, { 1, 9}, { 1, 12}, + { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 35, 0}, { 1, 46}, { 7, 38}, { 1, 39}, + { 19, 0}, + { 25, 0}, { 16, 38}, { 21, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, /* Row 145 */ + { 1, 7}, { 19, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, + { 1, 5}, { 64, 0}, + { 25, 0}, { 16, 38}, { 22, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, /* Row 146 */ + { 1, 7}, { 17, 4}, { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, + { 1, 5}, { 65, 0}, + { 64, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 15, 4}, /* Row 147 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 66, 0}, + { 65, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 13, 4}, /* Row 148 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 67, 0}, + { 66, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 11, 4}, /* Row 149 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 68, 0}, + { 67, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 9, 4}, /* Row 150 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 69, 0}, + { 68, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 7, 4}, /* Row 151 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 70, 0}, + { 69, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 5, 4}, /* Row 152 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 71, 0}, + { 70, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 3, 4}, /* Row 153 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 72, 0}, + { 71, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 1, 4}, /* Row 154 */ + { 1, 7}, { 1, 9}, { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 73, 0}, + { 72, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 16}, { 1, 7}, { 1, 9}, /* Row 155 */ + { 1, 12}, { 1, 13}, { 1, 6}, { 1, 4}, { 1, 5}, { 74, 0}, + { 73, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 15}, { 1, 103}, { 1, 12}, { 1, 13}, /* Row 156 */ + { 1, 6}, { 1, 4}, { 1, 5}, { 75, 0}, + { 74, 0}, { 1, 5}, { 3, 4}, { 1, 8}, { 1, 139}, { 1, 13}, { 1, 6}, { 1, 4}, /* Row 157 */ + { 1, 5}, { 76, 0}, + { 75, 0}, { 1, 5}, { 2, 4}, { 1, 3}, { 1, 140}, { 1, 6}, { 1, 4}, { 1, 5}, /* Row 158 */ + { 77, 0}, + { 76, 0}, { 1, 5}, { 4, 4}, { 1, 5}, { 78, 0} /* Row 159 */ +}; + +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 8 +# ifdef CONFIG_EXAMPLES_NXIMAGE_GREYSCALE + + { 76, 0}, { 1, 1}, { 1, 2}, { 1, 3}, { 4, 4}, { 1, 5}, { 76, 0}, /* Row 0 */ + { 75, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 5, 4}, { 1, 5}, { 75, 0}, /* Row 1 */ + { 74, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 9}, { 1, 10}, /* Row 2 */ + { 4, 4}, { 1, 5}, { 74, 0}, + { 73, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 3 */ + { 1, 12}, { 1, 13}, { 4, 4}, { 1, 5}, { 73, 0}, + { 72, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 4 */ + { 1, 7}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 72, 0}, + { 71, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 5 */ + { 1, 7}, { 2, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 71, 0}, + { 70, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 6 */ + { 1, 7}, { 4, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 70, 0}, + { 69, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 7 */ + { 1, 7}, { 6, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 69, 0}, + { 68, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 8 */ + { 1, 7}, { 8, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 68, 0}, + { 67, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 9 */ + { 1, 7}, { 10, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 67, 0}, + { 66, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 10 */ + { 1, 7}, { 12, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 66, 0}, + { 65, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 11 */ + { 1, 7}, { 14, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 65, 0}, + { 64, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 12 */ + { 1, 7}, { 16, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 64, 0}, + { 63, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 13 */ + { 1, 7}, { 18, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 63, 0}, + { 62, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 14 */ + { 1, 7}, { 20, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 62, 0}, + { 61, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 15 */ + { 1, 7}, { 22, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 61, 0}, + { 60, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 16 */ + { 1, 7}, { 24, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 60, 0}, + { 59, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 17 */ + { 1, 7}, { 26, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 59, 0}, + { 58, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 18 */ + { 1, 7}, { 28, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 26, 0}, + { 1, 14}, { 5, 15}, { 1, 14}, { 25, 0}, + { 57, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 19 */ + { 1, 7}, { 10, 4}, { 5, 16}, { 15, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, + { 1, 5}, { 23, 0}, { 1, 17}, { 9, 15}, { 1, 17}, { 23, 0}, + { 56, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, /* Row 20 */ + { 1, 7}, { 9, 4}, { 1, 16}, { 1, 18}, { 1, 19}, { 3, 20}, { 1, 19}, { 1, 18}, + { 1, 21}, { 14, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 22, 0}, + { 11, 15}, { 1, 17}, { 22, 0}, + { 23, 0}, { 1, 14}, { 5, 15}, { 1, 22}, { 25, 0}, { 1, 1}, { 1, 6}, { 1, 7}, /* Row 21 */ + { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 9, 4}, { 1, 16}, { 1, 23}, + { 7, 15}, { 1, 19}, { 1, 24}, { 14, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, + { 1, 5}, { 20, 0}, { 1, 14}, { 12, 15}, { 1, 17}, { 21, 0}, + { 21, 0}, { 1, 17}, { 9, 15}, { 1, 17}, { 22, 0}, { 1, 1}, { 1, 6}, { 1, 7}, /* Row 22 */ + { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 9, 4}, { 1, 16}, { 1, 23}, + { 9, 15}, { 1, 20}, { 1, 24}, { 4, 4}, { 1, 3}, { 9, 4}, { 1, 3}, { 1, 8}, + { 1, 13}, { 4, 4}, { 1, 5}, { 19, 0}, { 14, 15}, { 21, 0}, + { 21, 0}, { 11, 15}, { 1, 17}, { 20, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, /* Row 23 */ + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 10, 4}, { 1, 18}, { 11, 15}, { 1, 25}, + { 1, 26}, { 2, 27}, { 1, 28}, { 1, 29}, { 10, 4}, { 1, 3}, { 1, 8}, { 1, 13}, + { 4, 4}, { 1, 5}, { 17, 0}, { 1, 14}, { 5, 15}, { 1, 30}, { 2, 31}, { 1, 30}, + { 5, 15}, { 1, 14}, { 20, 0}, + { 20, 0}, { 1, 22}, { 12, 15}, { 1, 32}, { 4, 33}, { 1, 7}, { 13, 0}, { 1, 1}, /* Row 24 */ + { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 10, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 3, 30}, { 5, 15}, { 1, 34}, { 1, 35}, { 3, 27}, + { 1, 36}, { 10, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 16, 0}, + { 5, 15}, { 1, 37}, { 4, 38}, { 1, 37}, { 4, 15}, { 1, 39}, { 1, 40}, { 1, 41}, + { 18, 0}, + { 19, 0}, { 1, 14}, { 13, 15}, { 1, 31}, { 1, 40}, { 5, 33}, { 11, 0}, { 1, 1}, /* Row 25 */ + { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 11, 4}, + { 1, 42}, { 4, 15}, { 1, 31}, { 3, 38}, { 1, 37}, { 5, 15}, { 1, 43}, { 4, 27}, + { 1, 36}, { 10, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 14, 0}, + { 1, 14}, { 4, 15}, { 1, 30}, { 6, 38}, { 1, 30}, { 4, 15}, { 1, 22}, { 1, 33}, + { 1, 41}, { 17, 0}, + { 19, 0}, { 5, 15}, { 1, 30}, { 1, 44}, { 1, 34}, { 1, 31}, { 6, 15}, { 1, 45}, /* Row 26 */ + { 5, 33}, { 1, 7}, { 9, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, + { 1, 7}, { 1, 11}, { 1, 7}, { 11, 4}, { 1, 46}, { 1, 47}, { 4, 15}, { 1, 48}, + { 4, 38}, { 1, 37}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 36}, { 10, 4}, + { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 13, 0}, { 5, 15}, { 1, 34}, + { 6, 38}, { 1, 44}, { 4, 15}, { 1, 45}, { 2, 33}, { 1, 41}, { 16, 0}, + { 18, 0}, { 1, 14}, { 4, 15}, { 1, 37}, { 4, 38}, { 1, 31}, { 5, 15}, { 1, 31}, /* Row 27 */ + { 1, 40}, { 5, 33}, { 8, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, + { 1, 7}, { 1, 11}, { 1, 7}, { 12, 4}, { 1, 16}, { 1, 20}, { 3, 15}, { 1, 31}, + { 6, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 9, 4}, + { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 11, 0}, { 1, 14}, { 4, 15}, + { 1, 30}, { 7, 38}, { 1, 44}, { 4, 15}, { 1, 45}, { 3, 33}, { 16, 0}, + { 18, 0}, { 4, 15}, { 1, 30}, { 5, 38}, { 1, 48}, { 1, 30}, { 5, 15}, { 1, 45}, /* Row 28 */ + { 5, 33}, { 1, 7}, { 6, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, + { 1, 7}, { 1, 11}, { 1, 7}, { 13, 4}, { 1, 16}, { 1, 20}, { 3, 15}, { 1, 19}, + { 6, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, + { 10, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 10, 0}, { 5, 15}, + { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 22}, { 3, 33}, { 1, 7}, { 15, 0}, + { 18, 0}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, { 1, 31}, { 1, 40}, /* Row 29 */ + { 5, 33}, { 5, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 14, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 10, 4}, { 1, 3}, + { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 8, 0}, { 1, 14}, { 4, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 4, 33}, { 15, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 5, 15}, { 1, 45}, { 5, 33}, /* Row 30 */ + { 1, 7}, { 3, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 15, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 11, 4}, + { 1, 3}, { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 7, 0}, { 5, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 45}, { 5, 33}, { 1, 50}, { 14, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 34}, { 5, 15}, { 1, 31}, { 1, 40}, /* Row 31 */ + { 5, 33}, { 2, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 16, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 9, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 11, 4}, { 1, 3}, + { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 5, 0}, { 1, 14}, { 4, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 5, 33}, { 1, 7}, { 14, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 9, 38}, { 1, 30}, { 5, 15}, { 1, 45}, { 5, 33}, /* Row 32 */ + { 1, 7}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, + { 1, 7}, { 17, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 9, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 12, 4}, { 1, 3}, + { 1, 8}, { 1, 13}, { 4, 4}, { 1, 5}, { 4, 0}, { 5, 15}, { 1, 34}, { 7, 38}, + { 1, 30}, { 4, 15}, { 1, 45}, { 6, 33}, { 1, 50}, { 14, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 9, 38}, { 1, 34}, { 5, 15}, { 1, 31}, { 1, 40}, /* Row 33 */ + { 4, 33}, { 1, 51}, { 1, 52}, { 1, 7}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, + { 1, 7}, { 18, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 10, 38}, { 1, 30}, + { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 12, 4}, { 1, 3}, { 1, 8}, + { 1, 13}, { 4, 4}, { 1, 5}, { 2, 0}, { 1, 14}, { 4, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 15, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 10, 38}, { 1, 30}, { 5, 15}, { 1, 45}, { 3, 33}, /* Row 34 */ + { 1, 53}, { 1, 54}, { 1, 21}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 19, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 10, 38}, { 1, 34}, { 4, 15}, + { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 13, 4}, { 1, 3}, { 1, 8}, + { 1, 13}, { 4, 4}, { 1, 5}, { 1, 0}, { 5, 15}, { 1, 34}, { 7, 38}, { 1, 30}, + { 3, 15}, { 1, 55}, { 1, 56}, { 6, 33}, { 1, 7}, { 15, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 10, 38}, { 1, 34}, { 5, 15}, { 1, 31}, { 1, 40}, /* Row 35 */ + { 1, 33}, { 1, 53}, { 1, 57}, { 1, 27}, { 1, 28}, { 1, 58}, { 1, 7}, { 1, 11}, + { 1, 7}, { 20, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 11, 38}, { 1, 30}, + { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 13, 4}, { 1, 3}, { 1, 8}, + { 1, 13}, { 4, 4}, { 1, 59}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, + { 1, 31}, { 1, 60}, { 6, 33}, { 16, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 11, 38}, { 1, 30}, { 5, 15}, { 1, 61}, { 1, 53}, /* Row 36 */ + { 1, 57}, { 3, 27}, { 1, 62}, { 1, 56}, { 1, 7}, { 21, 4}, { 1, 16}, { 1, 20}, + { 2, 15}, { 1, 30}, { 11, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, + { 1, 28}, { 1, 49}, { 14, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 2, 4}, { 1, 21}, + { 1, 19}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 45}, { 6, 33}, + { 1, 7}, { 16, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 11, 38}, { 1, 34}, { 5, 15}, { 1, 63}, { 1, 35}, /* Row 37 */ + { 5, 27}, { 1, 64}, { 22, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 12, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 14, 4}, { 1, 3}, + { 1, 8}, { 1, 13}, { 1, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 17, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 12, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, /* Row 38 */ + { 1, 65}, { 1, 3}, { 21, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 12, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 15, 4}, + { 1, 3}, { 1, 8}, { 1, 66}, { 1, 19}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, + { 4, 15}, { 1, 45}, { 6, 33}, { 1, 7}, { 17, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 12, 38}, { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, /* Row 39 */ + { 4, 27}, { 1, 28}, { 1, 49}, { 21, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, + { 13, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 16, 4}, + { 1, 67}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, + { 6, 33}, { 18, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 13, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, /* Row 40 */ + { 1, 29}, { 1, 3}, { 20, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 13, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 15, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 45}, + { 6, 33}, { 1, 7}, { 18, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 13, 38}, { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, /* Row 41 */ + { 4, 27}, { 1, 28}, { 1, 49}, { 20, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, + { 14, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 14, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, + { 6, 33}, { 19, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 14, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, /* Row 42 */ + { 1, 29}, { 1, 3}, { 19, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 14, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 13, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 45}, + { 6, 33}, { 1, 7}, { 19, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 14, 38}, { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, /* Row 43 */ + { 4, 27}, { 1, 28}, { 1, 49}, { 19, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 68}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, + { 1, 3}, { 12, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, + { 1, 31}, { 1, 40}, { 6, 33}, { 20, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 15, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, /* Row 44 */ + { 1, 29}, { 1, 3}, { 18, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, + { 1, 69}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, + { 1, 49}, { 11, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, + { 4, 15}, { 1, 45}, { 6, 33}, { 1, 7}, { 20, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 68}, { 6, 38}, { 1, 34}, { 5, 15}, /* Row 45 */ + { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 18, 4}, { 1, 16}, { 1, 20}, + { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, + { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 10, 4}, { 1, 18}, { 4, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 21, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 69}, { 7, 38}, { 1, 30}, { 5, 15}, /* Row 46 */ + { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 17, 4}, { 1, 16}, { 1, 20}, { 2, 15}, + { 1, 30}, { 7, 38}, { 2, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, + { 4, 27}, { 1, 28}, { 1, 49}, { 9, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 45}, { 6, 33}, { 1, 7}, { 21, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 1, 34}, { 6, 38}, { 1, 34}, /* Row 47 */ + { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 17, 4}, { 1, 16}, + { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 1, 15}, { 1, 34}, { 7, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 8, 4}, { 1, 18}, + { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, + { 22, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 2, 30}, { 7, 38}, { 1, 30}, { 5, 15}, /* Row 48 */ + { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 16, 4}, { 1, 16}, { 1, 20}, { 2, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 1, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, + { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 7, 4}, { 1, 21}, { 1, 19}, + { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 70}, { 6, 33}, { 1, 7}, + { 22, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 1, 15}, { 1, 34}, { 6, 38}, /* Row 49 */ + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 16, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 6, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 1}, + { 1, 53}, { 5, 33}, { 23, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 1, 15}, { 1, 30}, { 7, 38}, /* Row 50 */ + { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 15, 4}, { 1, 16}, + { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 5, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, + { 1, 27}, { 1, 57}, { 1, 53}, { 3, 33}, { 1, 7}, { 23, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 34}, { 6, 38}, /* Row 51 */ + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 15, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 3, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 4, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, + { 2, 27}, { 1, 57}, { 1, 53}, { 2, 33}, { 24, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 30}, { 7, 38}, /* Row 52 */ + { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 14, 4}, { 1, 16}, + { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 3, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 3, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, + { 4, 27}, { 1, 57}, { 1, 53}, { 1, 7}, { 24, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 3, 15}, { 1, 34}, { 6, 38}, /* Row 53 */ + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 14, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 2, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, + { 5, 27}, { 1, 71}, { 1, 72}, { 24, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 3, 15}, { 1, 30}, { 7, 38}, /* Row 54 */ + { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 13, 4}, { 1, 16}, + { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 1, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, + { 6, 27}, { 1, 28}, { 1, 49}, { 1, 5}, { 23, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, { 1, 34}, { 6, 38}, /* Row 55 */ + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 13, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 4}, { 1, 18}, + { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 6, 27}, + { 1, 49}, { 1, 3}, { 1, 4}, { 1, 5}, { 22, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, { 1, 30}, { 7, 38}, /* Row 56 */ + { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 12, 4}, { 1, 16}, + { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 73}, { 1, 19}, + { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 36}, + { 1, 13}, { 3, 4}, { 1, 5}, { 21, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 5, 15}, { 1, 34}, { 6, 38}, /* Row 57 */ + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 12, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 6, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 74}, { 4, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 28}, { 1, 49}, + { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 20, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 5, 15}, { 1, 30}, { 7, 38}, /* Row 58 */ + { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 11, 4}, { 1, 16}, + { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 6, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 3, 27}, { 1, 35}, { 1, 34}, { 4, 15}, + { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, { 2, 3}, + { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 19, 0}, + { 17, 0}, { 1, 75}, { 1, 55}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 6, 15}, /* Row 59 */ + { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, + { 1, 49}, { 11, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 7, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 3, 27}, { 1, 43}, + { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, + { 1, 28}, { 1, 49}, { 2, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, + { 18, 0}, + { 16, 0}, { 1, 1}, { 1, 76}, { 1, 37}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, /* Row 60 */ + { 6, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, + { 1, 3}, { 10, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 3, 15}, { 1, 37}, { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 1, 27}, { 1, 35}, { 1, 34}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, + { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, { 1, 3}, { 3, 4}, { 1, 3}, { 1, 8}, + { 1, 13}, { 3, 4}, { 1, 5}, { 17, 0}, + { 15, 0}, { 1, 1}, { 1, 6}, { 1, 73}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, /* Row 61 */ + { 1, 30}, { 7, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, + { 4, 27}, { 1, 28}, { 1, 49}, { 10, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 77}, { 1, 78}, { 4, 15}, { 1, 34}, { 7, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 1, 79}, { 1, 43}, { 4, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 28}, { 1, 49}, { 5, 4}, + { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 16, 0}, + { 14, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, /* Row 62 */ + { 8, 38}, { 1, 30}, { 7, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 43}, + { 5, 27}, { 1, 29}, { 1, 3}, { 9, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 41}, { 1, 34}, { 3, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 80}, { 1, 34}, { 4, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, { 1, 3}, { 6, 4}, + { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 15, 0}, + { 13, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 9}, { 1, 77}, { 2, 15}, /* Row 63 */ + { 1, 30}, { 8, 38}, { 1, 30}, { 3, 15}, { 1, 37}, { 4, 15}, { 1, 34}, { 6, 38}, + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 9, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, + { 1, 81}, { 1, 43}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 68}, + { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, + { 1, 28}, { 1, 49}, { 8, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, + { 14, 0}, + { 12, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 82}, { 1, 83}, /* Row 64 */ + { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 77}, { 1, 78}, { 4, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, + { 8, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 1, 35}, { 1, 34}, { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, + { 9, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, + { 1, 3}, { 9, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 13, 0}, + { 11, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 85}, /* Row 65 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 41}, + { 1, 34}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, + { 4, 27}, { 1, 28}, { 1, 49}, { 8, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 1, 27}, { 1, 43}, { 4, 15}, + { 1, 34}, { 7, 38}, { 1, 30}, { 7, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, + { 1, 34}, { 1, 35}, { 5, 27}, { 1, 28}, { 1, 49}, { 11, 4}, { 1, 3}, { 1, 8}, + { 1, 13}, { 3, 4}, { 1, 5}, { 12, 0}, + { 10, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 66 */ + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, + { 1, 81}, { 1, 43}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 43}, + { 5, 27}, { 1, 29}, { 1, 3}, { 7, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 1, 27}, { 1, 35}, { 1, 34}, + { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 7, 15}, { 1, 34}, { 7, 38}, { 1, 30}, + { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, { 1, 3}, { 12, 4}, { 1, 3}, { 1, 8}, + { 1, 13}, { 3, 4}, { 1, 5}, { 11, 0}, + { 9, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 67 */ + { 1, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 1, 35}, { 1, 34}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 7, 4}, { 1, 16}, + { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 2, 27}, { 1, 43}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 28}, { 1, 49}, + { 14, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 10, 0}, + { 8, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 68 */ + { 2, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 1, 27}, { 1, 43}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 6, 4}, { 1, 16}, { 1, 20}, + { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 2, 27}, + { 1, 35}, { 1, 34}, { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 5, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, { 1, 3}, { 15, 4}, + { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 9, 0}, + { 7, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 69 */ + { 3, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 1, 27}, { 1, 35}, { 1, 34}, { 4, 15}, { 1, 34}, { 6, 38}, + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 6, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, + { 1, 81}, { 3, 27}, { 1, 43}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 3, 15}, + { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 28}, + { 1, 49}, { 17, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 8, 0}, + { 6, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 70 */ + { 4, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 2, 27}, { 1, 43}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 5, 4}, { 1, 16}, { 1, 20}, + { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 3, 27}, + { 1, 35}, { 1, 34}, { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 3, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, { 1, 3}, { 18, 4}, + { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 7, 0}, + { 5, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 71 */ + { 5, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 2, 27}, { 1, 35}, { 1, 34}, { 4, 15}, { 1, 34}, { 6, 38}, + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 5, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, + { 1, 81}, { 4, 27}, { 1, 43}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 1, 15}, + { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 28}, + { 1, 49}, { 20, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 6, 0}, + { 4, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 72 */ + { 6, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 3, 27}, { 1, 43}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 4, 4}, { 1, 16}, { 1, 20}, + { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 4, 27}, + { 1, 35}, { 1, 34}, { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 1, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, { 1, 3}, { 21, 4}, + { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 5, 0}, + { 3, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 73 */ + { 7, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 3, 27}, { 1, 35}, { 1, 34}, { 4, 15}, { 1, 34}, { 6, 38}, + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 4, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, + { 1, 81}, { 5, 27}, { 1, 43}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 69}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 28}, { 1, 49}, { 23, 4}, + { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, { 4, 0}, + { 2, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 74 */ + { 8, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 4, 27}, { 1, 43}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 5, 15}, { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 3, 4}, { 1, 16}, { 1, 20}, + { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 5, 27}, + { 1, 87}, { 1, 34}, { 3, 15}, { 1, 30}, { 15, 38}, { 1, 30}, { 4, 15}, { 1, 43}, + { 6, 27}, { 1, 29}, { 1, 3}, { 24, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, + { 1, 5}, { 3, 0}, + { 1, 0}, { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, /* Row 75 */ + { 9, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 4, 27}, { 1, 35}, { 1, 34}, { 4, 15}, { 1, 34}, { 6, 38}, + { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 3, 4}, + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, + { 1, 81}, { 6, 27}, { 1, 67}, { 4, 15}, { 1, 34}, { 13, 38}, { 1, 34}, { 4, 15}, + { 1, 34}, { 1, 35}, { 5, 27}, { 1, 28}, { 1, 49}, { 26, 4}, { 1, 3}, { 1, 8}, + { 1, 13}, { 3, 4}, { 1, 5}, { 2, 0}, + { 1, 1}, { 1, 6}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, { 10, 4}, /* Row 76 */ + { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, + { 1, 81}, { 5, 27}, { 1, 43}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, + { 1, 43}, { 5, 27}, { 1, 29}, { 1, 3}, { 2, 4}, { 1, 16}, { 1, 20}, { 2, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 1, 21}, + { 1, 19}, { 3, 15}, { 1, 30}, { 13, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, + { 1, 29}, { 1, 3}, { 27, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, { 1, 5}, + { 1, 0}, + { 1, 2}, { 1, 7}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, { 11, 4}, { 1, 16}, /* Row 77 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 5, 27}, { 1, 87}, { 1, 34}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, + { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 2, 4}, { 1, 16}, { 1, 20}, + { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, + { 1, 4}, { 1, 18}, { 4, 15}, { 1, 34}, { 11, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 5, 27}, { 1, 28}, { 1, 49}, { 29, 4}, { 1, 3}, { 1, 8}, { 1, 13}, + { 3, 4}, { 1, 5}, + { 1, 3}, { 1, 4}, { 1, 28}, { 1, 84}, { 1, 86}, { 12, 4}, { 1, 16}, { 1, 20}, /* Row 78 */ + { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, + { 1, 67}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, + { 1, 29}, { 1, 3}, { 1, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, + { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 1, 4}, { 1, 21}, { 1, 19}, + { 3, 15}, { 1, 30}, { 11, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, + { 1, 3}, { 30, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 3, 4}, + { 1, 4}, { 1, 88}, { 1, 89}, { 1, 86}, { 13, 4}, { 1, 16}, { 1, 20}, { 2, 15}, /* Row 79 */ + { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 1, 21}, + { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, { 1, 34}, { 1, 35}, + { 4, 27}, { 1, 28}, { 1, 49}, { 1, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 2, 4}, { 1, 6}, + { 4, 15}, { 1, 34}, { 9, 38}, { 1, 19}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, + { 1, 28}, { 1, 49}, { 32, 4}, { 1, 3}, { 1, 8}, { 1, 13}, { 1, 49}, { 1, 3}, + { 2, 4}, { 1, 90}, { 1, 8}, { 1, 3}, { 12, 4}, { 1, 16}, { 1, 20}, { 2, 15}, /* Row 80 */ + { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 1, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, + { 1, 29}, { 1, 3}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 2, 4}, { 1, 6}, { 4, 15}, { 1, 69}, + { 9, 38}, { 1, 31}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 29}, { 1, 3}, { 33, 4}, + { 1, 3}, { 1, 91}, { 1, 81}, { 1, 4}, + { 3, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 11, 4}, { 1, 16}, { 1, 20}, { 2, 15}, /* Row 81 */ + { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 1, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, { 1, 34}, + { 1, 35}, { 4, 27}, { 1, 28}, { 1, 49}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 1, 4}, { 1, 21}, + { 1, 19}, { 4, 15}, { 1, 34}, { 8, 38}, { 1, 92}, { 4, 15}, { 1, 68}, { 1, 93}, + { 6, 27}, { 1, 49}, { 33, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 56}, { 1, 8}, + { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 10, 4}, { 1, 16}, { 1, 20}, { 2, 15}, /* Row 82 */ + { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 2, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 5, 27}, + { 1, 29}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 6, 27}, { 1, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 10, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 49}, { 32, 4}, { 1, 3}, { 1, 8}, + { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, + { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 9, 4}, { 1, 16}, { 1, 20}, /* Row 83 */ + { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, + { 2, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, + { 1, 34}, { 1, 35}, { 4, 27}, { 1, 28}, { 1, 7}, { 1, 20}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 1, 21}, { 1, 19}, + { 4, 15}, { 1, 34}, { 10, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, + { 1, 29}, { 1, 3}, { 30, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, + { 1, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 8, 4}, { 1, 16}, /* Row 84 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 6, 27}, { 3, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, + { 1, 43}, { 5, 27}, { 1, 10}, { 1, 20}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 1, 67}, { 4, 15}, { 1, 30}, { 12, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 28}, { 1, 49}, { 29, 4}, { 1, 3}, + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 1, 0}, + { 2, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 7, 4}, { 1, 16}, /* Row 85 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 6, 27}, { 3, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 5, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 81}, { 1, 77}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 5, 27}, { 1, 87}, { 1, 34}, + { 4, 15}, { 1, 34}, { 12, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, + { 1, 29}, { 1, 3}, { 27, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, { 2, 0}, + { 3, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 6, 4}, { 1, 16}, /* Row 86 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 6, 27}, { 4, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, + { 1, 43}, { 4, 27}, { 1, 81}, { 1, 25}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 2, 15}, { 1, 25}, { 1, 81}, { 5, 27}, { 1, 43}, { 4, 15}, { 1, 30}, { 14, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 28}, { 1, 49}, { 26, 4}, { 1, 3}, + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 3, 0}, + { 4, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 5, 4}, { 1, 16}, /* Row 87 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 6, 27}, { 4, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 5, 15}, { 1, 34}, { 1, 35}, { 3, 27}, { 1, 81}, { 1, 25}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 4, 27}, { 1, 35}, { 1, 34}, + { 4, 15}, { 1, 34}, { 14, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, + { 1, 29}, { 1, 3}, { 24, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, { 4, 0}, + { 5, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 4, 4}, { 1, 16}, /* Row 88 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 6, 27}, { 5, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, + { 1, 43}, { 3, 27}, { 1, 81}, { 1, 25}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 2, 15}, { 1, 25}, { 1, 81}, { 4, 27}, { 1, 43}, { 4, 15}, { 1, 30}, { 16, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 28}, { 1, 49}, { 23, 4}, { 1, 3}, + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 5, 0}, + { 6, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 3, 4}, { 1, 16}, /* Row 89 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 6, 27}, { 5, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 5, 15}, { 1, 34}, { 1, 35}, { 2, 27}, { 1, 81}, { 1, 25}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 3, 27}, { 1, 35}, { 1, 34}, + { 4, 15}, { 1, 34}, { 7, 38}, { 1, 34}, { 1, 69}, { 7, 38}, { 1, 34}, { 4, 15}, + { 1, 34}, { 1, 35}, { 5, 27}, { 1, 29}, { 1, 3}, { 21, 4}, { 1, 3}, { 1, 8}, + { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 6, 0}, + { 7, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 2, 4}, { 1, 16}, /* Row 90 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 6, 27}, { 6, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, + { 1, 43}, { 2, 27}, { 1, 81}, { 1, 25}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, + { 2, 15}, { 1, 25}, { 1, 81}, { 3, 27}, { 1, 43}, { 4, 15}, { 1, 30}, { 8, 38}, + { 1, 30}, { 1, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, + { 1, 28}, { 1, 49}, { 20, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, { 7, 0}, + { 8, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 1, 4}, { 1, 16}, /* Row 91 */ + { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, + { 6, 27}, { 6, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 5, 15}, { 1, 34}, { 1, 35}, { 1, 27}, { 1, 81}, { 1, 25}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 2, 27}, { 1, 35}, { 1, 34}, + { 4, 15}, { 1, 34}, { 7, 38}, { 1, 34}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 29}, { 1, 3}, { 18, 4}, { 1, 3}, + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 8, 0}, + { 9, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 1, 16}, { 1, 20}, /* Row 92 */ + { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, + { 7, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 43}, + { 1, 27}, { 1, 81}, { 1, 25}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 2, 27}, { 1, 43}, { 4, 15}, { 1, 30}, { 8, 38}, { 1, 30}, + { 3, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 28}, + { 1, 49}, { 17, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, + { 1, 5}, { 9, 0}, + { 10, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 16}, { 1, 20}, { 2, 15}, /* Row 93 */ + { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 7, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, { 1, 34}, + { 1, 35}, { 1, 81}, { 1, 25}, { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, + { 1, 25}, { 1, 81}, { 1, 27}, { 1, 35}, { 1, 34}, { 4, 15}, { 1, 34}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, + { 5, 27}, { 1, 29}, { 1, 3}, { 15, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, + { 1, 7}, { 1, 4}, { 1, 5}, { 10, 0}, + { 11, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 73}, { 1, 20}, { 2, 15}, { 1, 30}, /* Row 94 */ + { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 8, 4}, { 1, 18}, + { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 43}, { 1, 81}, { 1, 25}, + { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 1, 27}, + { 1, 43}, { 4, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 5, 15}, { 1, 34}, { 7, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 28}, { 1, 49}, { 14, 4}, { 1, 3}, + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 11, 0}, + { 12, 0}, { 1, 5}, { 4, 4}, { 1, 57}, { 1, 77}, { 2, 15}, { 1, 30}, { 8, 38}, /* Row 95 */ + { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 8, 4}, { 1, 21}, { 1, 19}, + { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, { 1, 34}, { 1, 41}, { 1, 25}, + { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 1, 35}, + { 1, 34}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 34}, { 6, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 29}, { 1, 3}, { 12, 4}, + { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 12, 0}, + { 13, 0}, { 1, 5}, { 3, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, /* Row 96 */ + { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 9, 4}, { 1, 18}, { 4, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 78}, { 1, 77}, { 2, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 1, 43}, { 4, 15}, { 1, 30}, + { 8, 38}, { 1, 30}, { 7, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, + { 5, 27}, { 1, 28}, { 1, 49}, { 11, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, + { 1, 7}, { 1, 4}, { 1, 5}, { 13, 0}, + { 14, 0}, { 1, 5}, { 2, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, /* Row 97 */ + { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 9, 4}, { 1, 21}, { 1, 19}, + { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 5, 15}, { 1, 37}, { 3, 15}, { 1, 30}, + { 7, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 41}, { 1, 34}, { 4, 15}, { 1, 34}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 37}, { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 29}, { 1, 3}, { 9, 4}, { 1, 3}, + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 14, 0}, + { 15, 0}, { 1, 5}, { 1, 4}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, /* Row 98 */ + { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 10, 4}, { 1, 18}, { 4, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 8, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, + { 1, 77}, { 1, 78}, { 4, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, { 1, 78}, + { 1, 34}, { 3, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, + { 1, 28}, { 1, 49}, { 8, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, { 15, 0}, + { 16, 0}, { 1, 5}, { 1, 16}, { 1, 20}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, /* Row 99 */ + { 2, 15}, { 1, 25}, { 1, 81}, { 6, 27}, { 10, 4}, { 1, 21}, { 1, 19}, { 4, 15}, + { 1, 34}, { 6, 38}, { 1, 34}, { 8, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 3, 15}, + { 1, 37}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 94}, + { 1, 43}, { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, + { 5, 27}, { 1, 29}, { 1, 3}, { 6, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, + { 1, 7}, { 1, 4}, { 1, 5}, { 16, 0}, + { 17, 0}, { 1, 95}, { 1, 96}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, /* Row 100 */ + { 1, 25}, { 1, 81}, { 6, 27}, { 11, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, + { 1, 30}, { 7, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 7, 15}, { 1, 30}, { 8, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 1, 27}, { 1, 35}, { 1, 34}, { 3, 15}, { 1, 34}, + { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 28}, { 1, 49}, { 5, 4}, + { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 17, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 101 */ + { 6, 27}, { 11, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 7, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 7, 15}, { 1, 34}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 2, 27}, { 1, 43}, { 3, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 29}, { 1, 3}, { 3, 4}, + { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 18, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 102 */ + { 6, 27}, { 12, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 6, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 6, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, + { 1, 43}, { 3, 27}, { 1, 35}, { 1, 34}, { 3, 15}, { 1, 34}, { 7, 38}, { 1, 30}, + { 4, 15}, { 1, 43}, { 5, 27}, { 1, 28}, { 1, 49}, { 2, 4}, { 1, 3}, { 1, 8}, + { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 19, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 103 */ + { 6, 27}, { 12, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 6, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 6, 15}, { 1, 34}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 4, 27}, { 1, 43}, { 3, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 29}, { 2, 3}, { 1, 8}, + { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 20, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 104 */ + { 6, 27}, { 13, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, + { 1, 43}, { 5, 27}, { 1, 35}, { 1, 34}, { 3, 15}, { 1, 34}, { 7, 38}, { 1, 30}, + { 4, 15}, { 1, 43}, { 5, 27}, { 1, 28}, { 1, 49}, { 1, 8}, { 1, 7}, { 1, 11}, + { 1, 7}, { 1, 4}, { 1, 5}, { 21, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 105 */ + { 6, 27}, { 13, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 5, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 5, 15}, { 1, 34}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 6, 27}, { 1, 74}, { 3, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 36}, { 1, 7}, { 1, 11}, + { 1, 7}, { 1, 4}, { 1, 5}, { 22, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 106 */ + { 6, 27}, { 14, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 4, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, + { 1, 43}, { 6, 27}, { 1, 28}, { 1, 73}, { 1, 19}, { 3, 15}, { 1, 34}, { 7, 38}, + { 1, 30}, { 4, 15}, { 1, 43}, { 5, 27}, { 1, 54}, { 1, 97}, { 1, 7}, { 1, 4}, + { 1, 5}, { 23, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 107 */ + { 6, 27}, { 14, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 6, 27}, { 1, 29}, { 1, 4}, { 1, 18}, { 3, 15}, + { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 5, 27}, { 1, 98}, + { 1, 4}, { 1, 5}, { 24, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 108 */ + { 6, 27}, { 15, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 3, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, + { 1, 43}, { 6, 27}, { 1, 28}, { 1, 49}, { 1, 4}, { 1, 21}, { 1, 19}, { 3, 15}, + { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 4, 27}, { 1, 57}, { 1, 99}, + { 1, 9}, { 25, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 109 */ + { 6, 27}, { 15, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 3, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 3, 15}, { 1, 34}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 2, 4}, { 1, 18}, + { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, { 2, 27}, + { 1, 57}, { 1, 53}, { 2, 33}, { 25, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 110 */ + { 6, 27}, { 16, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, + { 1, 43}, { 6, 27}, { 1, 28}, { 1, 49}, { 3, 4}, { 1, 21}, { 1, 19}, { 3, 15}, + { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 1, 27}, { 1, 57}, { 1, 53}, + { 3, 33}, { 1, 7}, { 24, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 111 */ + { 6, 27}, { 16, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 2, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 2, 15}, { 1, 34}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 4, 4}, { 1, 18}, + { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 1}, { 1, 53}, + { 5, 33}, { 24, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 112 */ + { 6, 27}, { 17, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 1, 15}, + { 1, 30}, { 7, 38}, { 1, 30}, { 1, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, + { 1, 43}, { 6, 27}, { 1, 28}, { 1, 49}, { 5, 4}, { 1, 21}, { 1, 19}, { 3, 15}, + { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 70}, { 6, 33}, { 1, 7}, { 23, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 113 */ + { 6, 27}, { 17, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 1, 15}, { 1, 30}, { 7, 38}, { 1, 30}, { 1, 15}, { 1, 34}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 34}, { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 6, 4}, { 1, 18}, + { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, + { 23, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 114 */ + { 6, 27}, { 18, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 2, 30}, { 7, 38}, + { 2, 30}, { 8, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 28}, { 1, 49}, + { 7, 4}, { 1, 21}, { 1, 19}, { 3, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, + { 1, 45}, { 6, 33}, { 1, 7}, { 22, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 25}, { 1, 81}, /* Row 115 */ + { 6, 27}, { 18, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, + { 1, 30}, { 7, 38}, { 1, 30}, { 1, 34}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 8, 4}, { 1, 18}, { 3, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 22, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 77}, { 1, 100}, /* Row 116 */ + { 6, 27}, { 19, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 7, 38}, { 1, 69}, { 7, 38}, + { 1, 69}, { 8, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 28}, { 1, 49}, + { 9, 4}, { 1, 21}, { 1, 19}, { 3, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, + { 1, 45}, { 6, 33}, { 1, 7}, { 21, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 101}, /* Row 117 */ + { 1, 57}, { 5, 27}, { 19, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, + { 1, 68}, { 7, 38}, { 1, 68}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 34}, { 1, 35}, + { 6, 27}, { 1, 29}, { 1, 3}, { 10, 4}, { 1, 18}, { 3, 15}, { 1, 30}, { 7, 38}, + { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 21, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 118 */ + { 1, 53}, { 1, 57}, { 4, 27}, { 1, 8}, { 1, 3}, { 18, 4}, { 1, 18}, { 4, 15}, + { 1, 30}, { 22, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 28}, { 1, 49}, + { 11, 4}, { 1, 21}, { 1, 19}, { 3, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, + { 1, 45}, { 6, 33}, { 1, 7}, { 20, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 119 */ + { 1, 33}, { 1, 53}, { 1, 57}, { 3, 27}, { 1, 36}, { 1, 8}, { 1, 3}, { 17, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 20, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 12, 4}, { 1, 18}, { 3, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 20, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 120 */ + { 2, 33}, { 1, 53}, { 1, 57}, { 2, 27}, { 1, 49}, { 1, 13}, { 1, 8}, { 1, 3}, + { 17, 4}, { 1, 18}, { 4, 15}, { 1, 30}, { 20, 38}, { 1, 30}, { 4, 15}, { 1, 43}, + { 6, 27}, { 1, 28}, { 1, 49}, { 12, 4}, { 1, 3}, { 1, 79}, { 1, 63}, { 3, 15}, + { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 45}, { 6, 33}, { 1, 7}, { 19, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 121 */ + { 3, 33}, { 1, 53}, { 1, 57}, { 1, 27}, { 2, 4}, { 1, 13}, { 1, 8}, { 1, 3}, + { 16, 4}, { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 18, 38}, { 1, 34}, { 4, 15}, + { 1, 34}, { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 11, 4}, { 1, 3}, { 1, 8}, + { 1, 7}, { 1, 102}, { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, + { 1, 40}, { 6, 33}, { 19, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 122 */ + { 4, 33}, { 1, 53}, { 1, 62}, { 3, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 16, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 18, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, + { 1, 28}, { 1, 49}, { 11, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 79}, + { 1, 19}, { 3, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 45}, { 6, 33}, + { 1, 7}, { 18, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 123 */ + { 5, 33}, { 1, 103}, { 1, 3}, { 3, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 15, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 16, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 10, 4}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 1, 4}, { 1, 53}, { 3, 15}, { 1, 30}, { 7, 38}, { 1, 34}, + { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 18, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 124 */ + { 6, 33}, { 1, 95}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 15, 4}, { 1, 18}, + { 4, 15}, { 1, 30}, { 16, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, { 1, 28}, + { 1, 49}, { 10, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, + { 1, 5}, { 1, 27}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, { 1, 45}, + { 6, 33}, { 1, 7}, { 17, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 125 */ + { 6, 33}, { 1, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 14, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 14, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 9, 4}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 2, 0}, { 1, 14}, { 3, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 17, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 126 */ + { 6, 33}, { 2, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 14, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 14, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, + { 1, 28}, { 1, 49}, { 9, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, { 4, 0}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, + { 1, 45}, { 6, 33}, { 1, 7}, { 16, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 127 */ + { 6, 33}, { 3, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 13, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 12, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 8, 4}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 5, 0}, { 1, 14}, { 3, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 16, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 128 */ + { 6, 33}, { 4, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 13, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 12, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, + { 1, 28}, { 1, 49}, { 8, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, { 7, 0}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, + { 1, 45}, { 6, 33}, { 1, 7}, { 15, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 129 */ + { 6, 33}, { 5, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 12, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 10, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 7, 4}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 8, 0}, { 1, 14}, { 3, 15}, { 1, 30}, + { 7, 38}, { 1, 34}, { 4, 15}, { 1, 31}, { 1, 40}, { 6, 33}, { 15, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 130 */ + { 6, 33}, { 6, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 12, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 10, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, + { 1, 28}, { 1, 49}, { 7, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, { 10, 0}, { 4, 15}, { 1, 34}, { 7, 38}, { 1, 30}, { 4, 15}, + { 1, 22}, { 6, 33}, { 1, 104}, { 14, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 131 */ + { 6, 33}, { 7, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 11, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 8, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 6, 4}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 11, 0}, { 1, 14}, { 3, 15}, { 1, 30}, + { 7, 38}, { 1, 44}, { 4, 15}, { 1, 45}, { 6, 33}, { 1, 65}, { 14, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 132 */ + { 6, 33}, { 8, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 11, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 4, 15}, { 1, 43}, { 6, 27}, + { 1, 28}, { 1, 49}, { 6, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, { 13, 0}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 4, 15}, + { 1, 45}, { 7, 33}, { 14, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 133 */ + { 6, 33}, { 9, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 10, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 34}, { 6, 38}, { 1, 34}, { 4, 15}, { 1, 34}, + { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 5, 4}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 14, 0}, { 1, 14}, { 3, 15}, { 1, 30}, + { 6, 38}, { 1, 44}, { 3, 15}, { 1, 55}, { 1, 105}, { 7, 33}, { 1, 104}, { 13, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 134 */ + { 6, 33}, { 10, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 10, 4}, + { 1, 18}, { 4, 15}, { 1, 30}, { 1, 106}, { 4, 38}, { 1, 106}, { 1, 30}, { 4, 15}, + { 1, 43}, { 6, 27}, { 1, 28}, { 1, 49}, { 5, 4}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 16, 0}, { 4, 15}, { 1, 34}, { 5, 38}, + { 1, 30}, { 3, 15}, { 1, 31}, { 1, 60}, { 7, 33}, { 1, 7}, { 13, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 135 */ + { 6, 33}, { 11, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 9, 4}, + { 1, 21}, { 1, 19}, { 4, 15}, { 1, 30}, { 1, 34}, { 2, 38}, { 1, 34}, { 1, 30}, + { 4, 15}, { 1, 34}, { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, { 4, 4}, { 1, 3}, + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 17, 0}, { 1, 14}, + { 3, 15}, { 1, 30}, { 1, 34}, { 2, 38}, { 1, 34}, { 1, 30}, { 4, 15}, { 1, 45}, + { 8, 33}, { 1, 7}, { 13, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 136 */ + { 6, 33}, { 12, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 9, 4}, + { 1, 18}, { 6, 15}, { 2, 30}, { 6, 15}, { 1, 43}, { 6, 27}, { 1, 28}, { 1, 49}, + { 4, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, + { 19, 0}, { 5, 15}, { 2, 30}, { 5, 15}, { 1, 31}, { 1, 40}, { 8, 33}, { 1, 50}, + { 13, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 137 */ + { 6, 33}, { 13, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 8, 4}, + { 1, 21}, { 1, 19}, { 12, 15}, { 1, 34}, { 1, 35}, { 6, 27}, { 1, 29}, { 1, 3}, + { 3, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, + { 20, 0}, { 1, 14}, { 10, 15}, { 1, 39}, { 1, 107}, { 9, 33}, { 14, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 30}, { 2, 15}, { 1, 96}, { 1, 60}, /* Row 138 */ + { 6, 33}, { 14, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 8, 4}, + { 1, 18}, { 12, 15}, { 1, 43}, { 6, 27}, { 1, 28}, { 1, 49}, { 3, 4}, { 1, 3}, + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 22, 0}, { 9, 15}, + { 1, 39}, { 1, 107}, { 9, 33}, { 1, 7}, { 14, 0}, + { 18, 0}, { 3, 15}, { 1, 30}, { 8, 38}, { 1, 55}, { 2, 96}, { 1, 108}, { 1, 60}, /* Row 139 */ + { 6, 33}, { 15, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 7, 4}, + { 1, 16}, { 1, 23}, { 10, 15}, { 1, 109}, { 1, 81}, { 6, 27}, { 1, 29}, { 1, 3}, + { 2, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, + { 23, 0}, { 1, 28}, { 1, 110}, { 5, 15}, { 1, 39}, { 1, 111}, { 1, 105}, { 10, 33}, + { 15, 0}, + { 25, 0}, { 1, 59}, { 4, 40}, { 4, 60}, { 7, 33}, { 16, 0}, { 1, 5}, { 4, 4}, /* Row 140 */ + { 1, 13}, { 1, 8}, { 1, 3}, { 7, 4}, { 1, 16}, { 1, 18}, { 1, 19}, { 6, 15}, + { 1, 34}, { 1, 43}, { 1, 81}, { 6, 27}, { 1, 28}, { 1, 49}, { 2, 4}, { 1, 3}, + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 27, 0}, { 1, 112}, + { 1, 14}, { 1, 113}, { 1, 22}, { 1, 40}, { 1, 76}, { 10, 33}, { 1, 7}, { 15, 0}, + { 25, 0}, { 16, 33}, { 17, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, /* Row 141 */ + { 8, 4}, { 1, 21}, { 1, 18}, { 1, 19}, { 1, 77}, { 1, 25}, { 1, 34}, { 1, 43}, + { 1, 35}, { 8, 27}, { 1, 8}, { 1, 3}, { 1, 4}, { 1, 3}, { 1, 8}, { 1, 7}, + { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 30, 0}, { 1, 50}, { 13, 33}, { 16, 0}, + { 25, 0}, { 16, 33}, { 18, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, /* Row 142 */ + { 9, 4}, { 1, 16}, { 1, 10}, { 1, 66}, { 1, 81}, { 8, 27}, { 1, 36}, { 1, 8}, + { 1, 3}, { 1, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, + { 1, 5}, { 32, 0}, { 1, 7}, { 11, 33}, { 17, 0}, + { 25, 0}, { 16, 33}, { 19, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, /* Row 143 */ + { 9, 4}, { 1, 3}, { 1, 49}, { 1, 29}, { 1, 28}, { 5, 27}, { 1, 36}, { 1, 8}, + { 3, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, + { 34, 0}, { 10, 33}, { 18, 0}, + { 25, 0}, { 16, 33}, { 20, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, /* Row 144 */ + { 10, 4}, { 1, 3}, { 10, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, + { 1, 4}, { 1, 5}, { 35, 0}, { 1, 41}, { 7, 33}, { 1, 7}, { 19, 0}, + { 25, 0}, { 16, 33}, { 21, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, /* Row 145 */ + { 19, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, + { 64, 0}, + { 25, 0}, { 16, 33}, { 22, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, /* Row 146 */ + { 17, 4}, { 1, 3}, { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, + { 65, 0}, + { 64, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 15, 4}, { 1, 3}, /* Row 147 */ + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 66, 0}, + { 65, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 13, 4}, { 1, 3}, /* Row 148 */ + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 67, 0}, + { 66, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 11, 4}, { 1, 3}, /* Row 149 */ + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 68, 0}, + { 67, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 9, 4}, { 1, 3}, /* Row 150 */ + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 69, 0}, + { 68, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 7, 4}, { 1, 3}, /* Row 151 */ + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 70, 0}, + { 69, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 5, 4}, { 1, 3}, /* Row 152 */ + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 71, 0}, + { 70, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 3, 4}, { 1, 3}, /* Row 153 */ + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 72, 0}, + { 71, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 1, 4}, { 1, 3}, /* Row 154 */ + { 1, 8}, { 1, 7}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 73, 0}, + { 72, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 8}, { 1, 3}, { 1, 8}, { 1, 7}, /* Row 155 */ + { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, { 74, 0}, + { 73, 0}, { 1, 5}, { 4, 4}, { 1, 13}, { 1, 91}, { 1, 7}, { 1, 11}, { 1, 7}, /* Row 156 */ + { 1, 4}, { 1, 5}, { 75, 0}, + { 74, 0}, { 1, 5}, { 4, 4}, { 1, 114}, { 1, 11}, { 1, 7}, { 1, 4}, { 1, 5}, /* Row 157 */ + { 76, 0}, + { 75, 0}, { 1, 5}, { 2, 4}, { 1, 8}, { 1, 115}, { 1, 7}, { 1, 4}, { 1, 5}, /* Row 158 */ + { 77, 0}, + { 76, 0}, { 1, 5}, { 4, 4}, { 1, 5}, { 78, 0} /* Row 159 */ + +# else /* CONFIG_EXAMPLES_NXIMAGE_GREYSCALE */ + +static const struct pix_run_s g_nuttx[] = +{ + { 76, 0}, { 1, 1}, { 1, 2}, { 5, 3}, { 1, 4}, { 76, 0}, /* Row 0 */ + { 75, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 6, 3}, { 1, 4}, { 75, 0}, /* Row 1 */ + { 74, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 2, 6}, { 4, 3}, { 1, 4}, /* Row 2 */ + { 74, 0}, + { 73, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 8}, /* Row 3 */ + { 1, 6}, { 4, 3}, { 1, 4}, { 73, 0}, + { 72, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 4 */ + { 2, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 72, 0}, + { 71, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 5 */ + { 4, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 71, 0}, + { 70, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 6 */ + { 6, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 70, 0}, + { 69, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 7 */ + { 8, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 69, 0}, + { 68, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 8 */ + { 10, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 68, 0}, + { 67, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 9 */ + { 12, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 67, 0}, + { 66, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 10 */ + { 14, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 66, 0}, + { 65, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 11 */ + { 16, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 65, 0}, + { 64, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 12 */ + { 18, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 64, 0}, + { 63, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 13 */ + { 20, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 63, 0}, + { 62, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 14 */ + { 22, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 62, 0}, + { 61, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 15 */ + { 24, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 61, 0}, + { 60, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 16 */ + { 26, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 60, 0}, + { 59, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 17 */ + { 28, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 59, 0}, + { 58, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 18 */ + { 30, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 26, 0}, { 1, 9}, { 5, 10}, { 1, 9}, + { 25, 0}, + { 57, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 19 */ + { 10, 3}, { 5, 5}, { 17, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 23, 0}, { 1, 1}, + { 9, 10}, { 1, 1}, { 23, 0}, + { 56, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 20 */ + { 9, 3}, { 1, 5}, { 1, 11}, { 5, 12}, { 1, 11}, { 1, 13}, { 16, 3}, { 1, 6}, + { 4, 3}, { 1, 4}, { 22, 0}, { 11, 10}, { 1, 1}, { 22, 0}, + { 23, 0}, { 1, 9}, { 5, 10}, { 1, 14}, { 25, 0}, { 1, 1}, { 1, 2}, { 1, 5}, /* Row 21 */ + { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 9, 3}, { 1, 5}, { 1, 15}, { 7, 10}, + { 1, 12}, { 1, 16}, { 16, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 20, 0}, { 1, 9}, + { 12, 10}, { 1, 1}, { 21, 0}, + { 21, 0}, { 1, 1}, { 9, 10}, { 1, 1}, { 22, 0}, { 1, 1}, { 1, 2}, { 1, 5}, /* Row 22 */ + { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 9, 3}, { 1, 5}, { 1, 15}, { 9, 10}, + { 1, 12}, { 1, 16}, { 16, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 19, 0}, { 14, 10}, + { 21, 0}, + { 21, 0}, { 11, 10}, { 1, 1}, { 20, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, /* Row 23 */ + { 1, 7}, { 1, 2}, { 1, 5}, { 10, 3}, { 1, 11}, { 11, 10}, { 1, 12}, { 1, 7}, + { 3, 6}, { 1, 5}, { 12, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 17, 0}, { 1, 9}, + { 6, 10}, { 2, 12}, { 6, 10}, { 1, 9}, { 20, 0}, + { 20, 0}, { 1, 14}, { 12, 10}, { 1, 9}, { 4, 2}, { 1, 17}, { 13, 0}, { 1, 1}, /* Row 24 */ + { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 10, 3}, { 1, 13}, + { 1, 12}, { 12, 10}, { 1, 12}, { 5, 6}, { 12, 3}, { 1, 6}, { 4, 3}, { 1, 4}, + { 16, 0}, { 5, 10}, { 6, 12}, { 4, 10}, { 1, 12}, { 1, 18}, { 1, 1}, { 18, 0}, + { 19, 0}, { 1, 9}, { 13, 10}, { 1, 12}, { 1, 18}, { 5, 2}, { 11, 0}, { 1, 1}, /* Row 25 */ + { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 11, 3}, { 1, 19}, + { 4, 10}, { 5, 12}, { 5, 10}, { 1, 11}, { 5, 6}, { 12, 3}, { 1, 6}, { 4, 3}, + { 1, 4}, { 14, 0}, { 1, 9}, { 5, 10}, { 6, 12}, { 5, 10}, { 1, 14}, { 1, 2}, + { 1, 1}, { 17, 0}, + { 19, 0}, { 6, 10}, { 3, 12}, { 6, 10}, { 1, 14}, { 5, 2}, { 1, 17}, { 9, 0}, /* Row 26 */ + { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 11, 3}, + { 1, 5}, { 1, 14}, { 4, 10}, { 6, 12}, { 4, 10}, { 1, 12}, { 6, 6}, { 12, 3}, + { 1, 6}, { 4, 3}, { 1, 4}, { 13, 0}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 14}, + { 2, 2}, { 1, 1}, { 16, 0}, + { 18, 0}, { 1, 9}, { 4, 10}, { 6, 12}, { 5, 10}, { 1, 12}, { 1, 18}, { 5, 2}, /* Row 27 */ + { 8, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, + { 12, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 5, 10}, { 1, 11}, { 5, 6}, + { 1, 5}, { 12, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 11, 0}, { 1, 9}, { 5, 10}, + { 8, 12}, { 4, 10}, { 1, 14}, { 3, 2}, { 16, 0}, + { 18, 0}, { 5, 10}, { 6, 12}, { 6, 10}, { 1, 14}, { 5, 2}, { 1, 17}, { 6, 0}, /* Row 28 */ + { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 13, 3}, + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 6, 6}, { 13, 3}, + { 1, 6}, { 4, 3}, { 1, 4}, { 10, 0}, { 5, 10}, { 8, 12}, { 5, 10}, { 1, 14}, + { 3, 2}, { 1, 17}, { 15, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 1, 18}, { 5, 2}, { 5, 0}, /* Row 29 */ + { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 14, 3}, + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 5, 6}, { 1, 5}, + { 13, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 8, 0}, { 1, 9}, { 5, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 1, 18}, { 4, 2}, { 15, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 6, 10}, { 1, 14}, { 5, 2}, { 1, 17}, { 3, 0}, /* Row 30 */ + { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 15, 3}, + { 1, 5}, { 1, 12}, { 3, 10}, { 9, 12}, { 4, 10}, { 1, 12}, { 6, 6}, { 14, 3}, + { 1, 6}, { 4, 3}, { 1, 4}, { 7, 0}, { 5, 10}, { 8, 12}, { 5, 10}, { 1, 14}, + { 5, 2}, { 1, 1}, { 14, 0}, + { 18, 0}, { 4, 10}, { 9, 12}, { 5, 10}, { 1, 12}, { 1, 18}, { 5, 2}, { 2, 0}, /* Row 31 */ + { 1, 1}, { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 16, 3}, + { 1, 5}, { 1, 12}, { 3, 10}, { 9, 12}, { 5, 10}, { 1, 11}, { 5, 6}, { 1, 5}, + { 14, 3}, { 1, 6}, { 4, 3}, { 1, 4}, { 5, 0}, { 1, 9}, { 5, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 1, 18}, { 5, 2}, { 1, 17}, { 14, 0}, + { 18, 0}, { 4, 10}, { 9, 12}, { 6, 10}, { 1, 14}, { 5, 2}, { 1, 17}, { 1, 1}, /* Row 32 */ + { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 17, 3}, { 1, 5}, + { 1, 12}, { 3, 10}, { 10, 12}, { 4, 10}, { 1, 12}, { 6, 6}, { 15, 3}, { 1, 6}, + { 4, 3}, { 1, 4}, { 4, 0}, { 5, 10}, { 8, 12}, { 5, 10}, { 1, 14}, { 6, 2}, + { 1, 1}, { 14, 0}, + { 18, 0}, { 4, 10}, { 10, 12}, { 5, 10}, { 1, 12}, { 1, 18}, { 4, 2}, { 1, 18}, /* Row 33 */ + { 1, 2}, { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 18, 3}, { 1, 5}, + { 1, 12}, { 3, 10}, { 10, 12}, { 5, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 15, 3}, + { 1, 6}, { 4, 3}, { 1, 4}, { 2, 0}, { 1, 9}, { 5, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 1, 18}, { 6, 2}, { 15, 0}, + { 18, 0}, { 4, 10}, { 10, 12}, { 6, 10}, { 1, 14}, { 3, 2}, { 1, 20}, { 1, 6}, /* Row 34 */ + { 1, 5}, { 2, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 19, 3}, { 1, 5}, { 1, 12}, + { 3, 10}, { 11, 12}, { 4, 10}, { 1, 12}, { 6, 6}, { 16, 3}, { 1, 6}, { 4, 3}, + { 1, 4}, { 1, 0}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 7, 2}, { 1, 17}, + { 15, 0}, + { 18, 0}, { 4, 10}, { 11, 12}, { 5, 10}, { 1, 12}, { 1, 18}, { 1, 2}, { 1, 20}, /* Row 35 */ + { 3, 6}, { 1, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 20, 3}, { 1, 5}, { 1, 12}, + { 3, 10}, { 11, 12}, { 5, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 16, 3}, { 1, 6}, + { 4, 3}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 7, 2}, { 16, 0}, + { 18, 0}, { 4, 10}, { 11, 12}, { 6, 10}, { 1, 14}, { 1, 20}, { 5, 6}, { 1, 2}, /* Row 36 */ + { 1, 5}, { 21, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 12, 12}, { 4, 10}, { 1, 12}, + { 6, 6}, { 17, 3}, { 1, 6}, { 2, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, + { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, { 16, 0}, + { 18, 0}, { 4, 10}, { 12, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 1, 5}, { 22, 3}, /* Row 37 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 12, 12}, { 5, 10}, { 1, 11}, { 5, 6}, { 1, 5}, + { 17, 3}, { 1, 6}, { 1, 3}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, + { 1, 18}, { 6, 2}, { 17, 0}, + { 18, 0}, { 4, 10}, { 12, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 22, 3}, /* Row 38 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 13, 12}, { 4, 10}, { 1, 12}, { 6, 6}, { 18, 3}, + { 1, 6}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, + { 17, 0}, + { 18, 0}, { 4, 10}, { 13, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 22, 3}, { 1, 5}, /* Row 39 */ + { 1, 12}, { 3, 10}, { 13, 12}, { 5, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 17, 3}, + { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, { 6, 2}, { 18, 0}, + { 18, 0}, { 4, 10}, { 13, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 21, 3}, /* Row 40 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 14, 12}, { 4, 10}, { 1, 12}, { 6, 6}, { 16, 3}, + { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, + { 18, 0}, + { 18, 0}, { 4, 10}, { 14, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 21, 3}, { 1, 5}, /* Row 41 */ + { 1, 12}, { 3, 10}, { 14, 12}, { 5, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 15, 3}, + { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, { 6, 2}, { 19, 0}, + { 18, 0}, { 4, 10}, { 14, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 20, 3}, /* Row 42 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 15, 12}, { 4, 10}, { 1, 12}, { 6, 6}, { 14, 3}, + { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, + { 19, 0}, + { 18, 0}, { 4, 10}, { 15, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 20, 3}, { 1, 5}, /* Row 43 */ + { 1, 12}, { 3, 10}, { 15, 12}, { 5, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 13, 3}, + { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, { 6, 2}, { 20, 0}, + { 18, 0}, { 4, 10}, { 15, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 19, 3}, /* Row 44 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 1, 10}, { 8, 12}, { 4, 10}, { 1, 12}, + { 6, 6}, { 12, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 14}, + { 6, 2}, { 1, 17}, { 20, 0}, + { 18, 0}, { 4, 10}, { 16, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 19, 3}, { 1, 5}, /* Row 45 */ + { 1, 12}, { 3, 10}, { 7, 12}, { 1, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 5, 6}, + { 1, 5}, { 11, 3}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, + { 6, 2}, { 21, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 1, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, /* Row 46 */ + { 1, 5}, { 18, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 2, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 6, 6}, { 10, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, + { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, { 21, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 1, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, /* Row 47 */ + { 18, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 2, 10}, { 8, 12}, { 5, 10}, + { 1, 11}, { 5, 6}, { 1, 5}, { 9, 3}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 1, 18}, { 6, 2}, { 22, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 2, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, /* Row 48 */ + { 1, 5}, { 17, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 6, 6}, { 8, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, + { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, { 22, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 2, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, /* Row 49 */ + { 17, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 8, 12}, { 5, 10}, + { 1, 11}, { 5, 6}, { 1, 5}, { 7, 3}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 1, 21}, { 1, 20}, { 5, 2}, { 23, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, /* Row 50 */ + { 1, 5}, { 16, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 4, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 6, 6}, { 6, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, + { 5, 10}, { 1, 11}, { 2, 6}, { 1, 20}, { 3, 2}, { 1, 17}, { 23, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, /* Row 51 */ + { 16, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 4, 10}, { 8, 12}, { 5, 10}, + { 1, 11}, { 5, 6}, { 1, 5}, { 5, 3}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 4, 6}, { 1, 20}, { 2, 2}, { 24, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 4, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, /* Row 52 */ + { 1, 5}, { 15, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 5, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 6, 6}, { 4, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, + { 5, 10}, { 1, 11}, { 5, 6}, { 1, 20}, { 1, 17}, { 24, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, /* Row 53 */ + { 15, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 5, 10}, { 8, 12}, { 5, 10}, + { 1, 11}, { 5, 6}, { 1, 5}, { 3, 3}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 25, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, /* Row 54 */ + { 1, 5}, { 14, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 6, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 6, 6}, { 2, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, + { 5, 10}, { 1, 11}, { 7, 6}, { 1, 3}, { 1, 4}, { 23, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 5, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, /* Row 55 */ + { 14, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 6, 10}, { 8, 12}, { 5, 10}, + { 1, 11}, { 5, 6}, { 1, 5}, { 1, 3}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 3, 3}, { 1, 4}, { 22, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 6, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, /* Row 56 */ + { 1, 5}, { 13, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 7, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 6, 6}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, + { 1, 11}, { 8, 6}, { 3, 3}, { 1, 4}, { 21, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 6, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, /* Row 57 */ + { 13, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 7, 10}, { 8, 12}, { 5, 10}, + { 1, 11}, { 5, 6}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 7, 6}, + { 2, 3}, { 1, 6}, { 3, 3}, { 1, 4}, { 20, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 7, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, /* Row 58 */ + { 1, 5}, { 12, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 8, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 5, 6}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 6, 6}, { 1, 5}, { 3, 3}, { 1, 6}, { 3, 3}, { 1, 4}, { 19, 0}, + { 17, 0}, { 1, 22}, { 1, 12}, { 3, 10}, { 8, 12}, { 7, 10}, { 8, 12}, { 5, 10}, /* Row 59 */ + { 1, 12}, { 6, 6}, { 12, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 8, 10}, + { 8, 12}, { 5, 10}, { 1, 11}, { 3, 6}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 5, 3}, { 1, 6}, { 3, 3}, { 1, 4}, { 18, 0}, + { 16, 0}, { 1, 1}, { 1, 18}, { 1, 12}, { 3, 10}, { 8, 12}, { 8, 10}, { 7, 12}, /* Row 60 */ + { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 11, 3}, { 1, 5}, { 1, 12}, { 3, 10}, + { 7, 12}, { 4, 10}, { 1, 12}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 3, 6}, + { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 1, 5}, { 6, 3}, + { 1, 6}, { 3, 3}, { 1, 4}, { 17, 0}, + { 15, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 8, 10}, /* Row 61 */ + { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 11, 3}, { 1, 5}, { 1, 12}, { 3, 10}, + { 7, 12}, { 3, 10}, { 1, 12}, { 1, 11}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 1, 6}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 7, 6}, { 8, 3}, + { 1, 6}, { 3, 3}, { 1, 4}, { 16, 0}, + { 14, 0}, { 1, 1}, { 1, 2}, { 2, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 9, 10}, /* Row 62 */ + { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 10, 3}, { 1, 5}, { 1, 12}, + { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 1, 21}, { 1, 12}, { 4, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 1, 23}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 6, 6}, { 1, 5}, { 9, 3}, { 1, 6}, { 3, 3}, { 1, 4}, { 15, 0}, + { 13, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 12}, { 3, 10}, /* Row 63 */ + { 8, 12}, { 4, 10}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, + { 10, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 1, 6}, + { 1, 11}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 5, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 11, 3}, { 1, 6}, { 3, 3}, { 1, 4}, { 14, 0}, + { 12, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 24}, { 1, 12}, /* Row 64 */ + { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 1, 11}, { 5, 10}, { 7, 12}, { 6, 10}, + { 1, 11}, { 5, 6}, { 1, 5}, { 9, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, + { 3, 10}, { 1, 12}, { 2, 6}, { 1, 12}, { 4, 10}, { 8, 12}, { 9, 10}, { 8, 12}, + { 5, 10}, { 1, 11}, { 6, 6}, { 1, 5}, { 12, 3}, { 1, 6}, { 3, 3}, { 1, 4}, + { 13, 0}, + { 11, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 1, 3}, /* Row 65 */ + { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 1, 21}, { 1, 12}, { 4, 10}, + { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 9, 3}, { 1, 5}, { 1, 12}, { 3, 10}, + { 7, 12}, { 3, 10}, { 1, 12}, { 2, 6}, { 1, 11}, { 4, 10}, { 8, 12}, { 9, 10}, + { 8, 12}, { 4, 10}, { 1, 12}, { 7, 6}, { 14, 3}, { 1, 6}, { 3, 3}, { 1, 4}, + { 12, 0}, + { 10, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 1, 3}, /* Row 66 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 1, 6}, { 1, 11}, + { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 8, 3}, { 1, 5}, + { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 3, 6}, { 1, 12}, { 4, 10}, + { 8, 12}, { 7, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 1, 5}, { 15, 3}, + { 1, 6}, { 3, 3}, { 1, 4}, { 11, 0}, + { 9, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 2, 3}, /* Row 67 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 2, 6}, { 1, 12}, + { 4, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 8, 3}, { 1, 5}, { 1, 12}, + { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 3, 6}, { 1, 11}, { 4, 10}, { 8, 12}, + { 7, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 7, 6}, { 17, 3}, { 1, 6}, { 3, 3}, + { 1, 4}, { 10, 0}, + { 8, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 3, 3}, /* Row 68 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 2, 6}, { 1, 11}, + { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 7, 3}, { 1, 5}, + { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 4, 6}, { 1, 12}, { 4, 10}, + { 8, 12}, { 5, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 1, 5}, { 18, 3}, + { 1, 6}, { 3, 3}, { 1, 4}, { 9, 0}, + { 7, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 4, 3}, /* Row 69 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 3, 6}, { 1, 12}, + { 4, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 7, 3}, { 1, 5}, { 1, 12}, + { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 4, 6}, { 1, 11}, { 4, 10}, { 8, 12}, + { 5, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 7, 6}, { 20, 3}, { 1, 6}, { 3, 3}, + { 1, 4}, { 8, 0}, + { 6, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 5, 3}, /* Row 70 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 3, 6}, { 1, 11}, + { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 6, 3}, { 1, 5}, + { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 5, 6}, { 1, 12}, { 4, 10}, + { 8, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 1, 5}, { 21, 3}, + { 1, 6}, { 3, 3}, { 1, 4}, { 7, 0}, + { 5, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 6, 3}, /* Row 71 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 4, 6}, { 1, 12}, + { 4, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 6, 3}, { 1, 5}, { 1, 12}, + { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 5, 6}, { 1, 11}, { 4, 10}, { 8, 12}, + { 3, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 7, 6}, { 23, 3}, { 1, 6}, { 3, 3}, + { 1, 4}, { 6, 0}, + { 4, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 7, 3}, /* Row 72 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 4, 6}, { 1, 11}, + { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 5, 3}, { 1, 5}, + { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 6, 6}, { 1, 12}, { 4, 10}, + { 8, 12}, { 1, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 1, 5}, { 24, 3}, + { 1, 6}, { 3, 3}, { 1, 4}, { 5, 0}, + { 3, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 8, 3}, /* Row 73 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 5, 6}, { 1, 12}, + { 4, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 5, 3}, { 1, 5}, { 1, 12}, + { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 6, 6}, { 1, 11}, { 4, 10}, { 8, 12}, + { 1, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 7, 6}, { 26, 3}, { 1, 6}, { 3, 3}, + { 1, 4}, { 4, 0}, + { 2, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 9, 3}, /* Row 74 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 5, 6}, { 1, 11}, + { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 4, 3}, { 1, 5}, + { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 1, 12}, { 4, 10}, + { 15, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 1, 5}, { 27, 3}, { 1, 6}, { 3, 3}, + { 1, 4}, { 3, 0}, + { 1, 0}, { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 10, 3}, /* Row 75 */ + { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 6, 6}, { 1, 12}, + { 4, 10}, { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 4, 3}, { 1, 5}, { 1, 12}, + { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 1, 11}, { 4, 10}, { 15, 12}, + { 4, 10}, { 1, 12}, { 7, 6}, { 29, 3}, { 1, 6}, { 3, 3}, { 1, 4}, { 2, 0}, + { 1, 1}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 11, 3}, { 1, 5}, /* Row 76 */ + { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 6, 6}, { 1, 11}, { 5, 10}, + { 7, 12}, { 6, 10}, { 1, 11}, { 5, 6}, { 1, 5}, { 3, 3}, { 1, 5}, { 1, 12}, + { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 1, 13}, { 1, 12}, { 4, 10}, + { 13, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 1, 5}, { 30, 3}, { 1, 6}, { 3, 3}, + { 1, 4}, { 1, 0}, + { 1, 2}, { 1, 5}, { 1, 3}, { 1, 6}, { 1, 2}, { 12, 3}, { 1, 5}, { 1, 12}, /* Row 77 */ + { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 1, 12}, { 4, 10}, { 8, 12}, + { 5, 10}, { 1, 12}, { 6, 6}, { 3, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, + { 3, 10}, { 1, 12}, { 7, 6}, { 1, 3}, { 1, 11}, { 4, 10}, { 13, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 32, 3}, { 1, 6}, { 3, 3}, { 1, 4}, + { 2, 3}, { 1, 6}, { 1, 2}, { 13, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, /* Row 78 */ + { 3, 10}, { 1, 12}, { 7, 6}, { 1, 11}, { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, + { 5, 6}, { 1, 5}, { 2, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 7, 6}, { 1, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 11, 12}, { 5, 10}, + { 1, 11}, { 6, 6}, { 1, 5}, { 33, 3}, { 1, 6}, { 3, 3}, + { 1, 3}, { 1, 5}, { 1, 18}, { 14, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, /* Row 79 */ + { 3, 10}, { 1, 12}, { 7, 6}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, + { 1, 12}, { 6, 6}, { 2, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 7, 6}, { 2, 3}, { 1, 11}, { 4, 10}, { 11, 12}, { 4, 10}, { 1, 12}, + { 7, 6}, { 35, 3}, { 1, 6}, { 2, 3}, + { 2, 3}, { 1, 6}, { 14, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, /* Row 80 */ + { 1, 12}, { 7, 6}, { 1, 3}, { 1, 11}, { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, + { 5, 6}, { 1, 5}, { 1, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 7, 6}, { 2, 3}, { 1, 11}, { 5, 10}, { 10, 12}, { 4, 10}, { 1, 11}, + { 6, 6}, { 1, 5}, { 35, 3}, { 1, 5}, { 1, 6}, { 1, 3}, + { 3, 3}, { 1, 6}, { 13, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, /* Row 81 */ + { 1, 12}, { 7, 6}, { 1, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, + { 1, 12}, { 6, 6}, { 1, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 7, 6}, { 1, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 10, 12}, { 4, 10}, + { 1, 12}, { 1, 21}, { 6, 6}, { 36, 3}, { 1, 7}, { 1, 2}, { 1, 5}, + { 4, 3}, { 1, 6}, { 12, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, /* Row 82 */ + { 1, 12}, { 7, 6}, { 2, 3}, { 1, 11}, { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, + { 5, 6}, { 2, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 7, 6}, + { 1, 3}, { 1, 11}, { 5, 10}, { 10, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 35, 3}, + { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 4, 3}, { 1, 6}, { 11, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, /* Row 83 */ + { 3, 10}, { 1, 12}, { 7, 6}, { 2, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, + { 5, 10}, { 1, 12}, { 6, 6}, { 1, 5}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 7, 6}, { 1, 13}, { 1, 12}, { 4, 10}, { 12, 12}, { 4, 10}, { 1, 12}, + { 6, 6}, { 1, 5}, { 33, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, + { 1, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 10, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 84 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 3, 3}, { 1, 11}, { 5, 10}, { 7, 12}, + { 6, 10}, { 1, 11}, { 5, 6}, { 1, 13}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 7, 6}, { 1, 11}, { 5, 10}, { 12, 12}, { 5, 10}, { 1, 11}, { 6, 6}, + { 32, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 1, 0}, + { 2, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 9, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 85 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 3, 3}, { 1, 13}, { 1, 12}, { 4, 10}, + { 8, 12}, { 5, 10}, { 1, 12}, { 6, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 7, 6}, { 1, 12}, { 4, 10}, { 14, 12}, { 4, 10}, { 1, 12}, { 6, 6}, + { 1, 5}, { 30, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 2, 0}, + { 3, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 8, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 86 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 4, 3}, { 1, 11}, { 5, 10}, { 7, 12}, + { 6, 10}, { 1, 11}, { 5, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, + { 6, 6}, { 1, 11}, { 5, 10}, { 14, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 29, 3}, + { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 3, 0}, + { 4, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 7, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 87 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 4, 3}, { 1, 13}, { 1, 12}, { 4, 10}, + { 8, 12}, { 5, 10}, { 1, 12}, { 5, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 6, 6}, { 1, 12}, { 4, 10}, { 16, 12}, { 4, 10}, { 1, 12}, { 6, 6}, + { 1, 5}, { 27, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 4, 0}, + { 5, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 6, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 88 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 5, 3}, { 1, 11}, { 5, 10}, { 7, 12}, + { 6, 10}, { 1, 11}, { 4, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, + { 5, 6}, { 1, 11}, { 5, 10}, { 16, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 26, 3}, + { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 5, 0}, + { 6, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 5, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 89 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 5, 3}, { 1, 13}, { 1, 12}, { 4, 10}, + { 8, 12}, { 5, 10}, { 1, 12}, { 4, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 5, 6}, { 1, 12}, { 4, 10}, { 9, 12}, { 1, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 6, 6}, { 1, 5}, { 24, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 6, 0}, + { 7, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 4, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 90 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 6, 3}, { 1, 11}, { 5, 10}, { 7, 12}, + { 6, 10}, { 1, 11}, { 3, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, + { 4, 6}, { 1, 11}, { 5, 10}, { 8, 12}, { 2, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 6, 6}, { 23, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 7, 0}, + { 8, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 3, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 91 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 6, 3}, { 1, 13}, { 1, 12}, { 4, 10}, + { 8, 12}, { 5, 10}, { 1, 12}, { 3, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 4, 6}, { 1, 12}, { 4, 10}, { 9, 12}, { 3, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 6, 6}, { 1, 5}, { 21, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 8, 0}, + { 9, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 2, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 92 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 7, 3}, { 1, 11}, { 5, 10}, { 7, 12}, + { 6, 10}, { 1, 11}, { 2, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, + { 3, 6}, { 1, 11}, { 5, 10}, { 8, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 6, 6}, { 20, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 9, 0}, + { 10, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 1, 3}, { 1, 5}, { 1, 12}, { 3, 10}, /* Row 93 */ + { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 7, 3}, { 1, 13}, { 1, 12}, { 4, 10}, + { 8, 12}, { 5, 10}, { 1, 12}, { 2, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, + { 1, 12}, { 3, 6}, { 1, 12}, { 4, 10}, { 9, 12}, { 5, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 6, 6}, { 1, 5}, { 18, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 10, 0}, + { 11, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, /* Row 94 */ + { 3, 10}, { 1, 12}, { 7, 6}, { 8, 3}, { 1, 11}, { 5, 10}, { 7, 12}, { 6, 10}, + { 1, 11}, { 1, 6}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 2, 6}, + { 1, 11}, { 5, 10}, { 8, 12}, { 6, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, + { 17, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 11, 0}, + { 12, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, /* Row 95 */ + { 1, 12}, { 7, 6}, { 8, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, + { 1, 12}, { 1, 21}, { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 2, 6}, + { 1, 12}, { 4, 10}, { 9, 12}, { 7, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 6, 6}, + { 1, 5}, { 15, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 12, 0}, + { 13, 0}, { 1, 4}, { 3, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, /* Row 96 */ + { 1, 12}, { 7, 6}, { 9, 3}, { 1, 11}, { 5, 10}, { 7, 12}, { 6, 10}, { 1, 11}, + { 1, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 1, 6}, { 1, 11}, { 5, 10}, + { 8, 12}, { 8, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 14, 3}, { 1, 7}, + { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 13, 0}, + { 14, 0}, { 1, 4}, { 2, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, /* Row 97 */ + { 1, 12}, { 7, 6}, { 9, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, + { 1, 12}, { 4, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 1, 21}, { 1, 12}, { 4, 10}, + { 9, 12}, { 4, 10}, { 1, 12}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 6, 6}, + { 1, 5}, { 12, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 14, 0}, + { 15, 0}, { 1, 4}, { 1, 3}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, /* Row 98 */ + { 1, 12}, { 7, 6}, { 10, 3}, { 1, 11}, { 5, 10}, { 7, 12}, { 10, 10}, { 7, 12}, + { 3, 10}, { 1, 12}, { 1, 11}, { 5, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 1, 12}, + { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 11, 3}, { 1, 7}, { 1, 2}, + { 1, 5}, { 1, 3}, { 1, 4}, { 15, 0}, + { 16, 0}, { 1, 4}, { 1, 5}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, /* Row 99 */ + { 7, 6}, { 10, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 9, 10}, { 7, 12}, + { 4, 10}, { 1, 12}, { 4, 10}, { 9, 12}, { 4, 10}, { 1, 12}, { 1, 6}, { 1, 11}, + { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 6, 6}, { 1, 5}, { 9, 3}, { 1, 7}, + { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 16, 0}, + { 17, 0}, { 1, 4}, { 1, 12}, { 3, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, /* Row 100 */ + { 11, 3}, { 1, 11}, { 5, 10}, { 7, 12}, { 9, 10}, { 7, 12}, { 9, 10}, { 8, 12}, + { 5, 10}, { 1, 11}, { 2, 6}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 6, 6}, { 8, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 17, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 11, 3}, { 1, 13}, /* Row 101 */ + { 1, 12}, { 4, 10}, { 8, 12}, { 8, 10}, { 7, 12}, { 8, 10}, { 9, 12}, { 4, 10}, + { 1, 12}, { 3, 6}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 6, 6}, + { 1, 5}, { 6, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 18, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 12, 3}, { 1, 11}, /* Row 102 */ + { 5, 10}, { 7, 12}, { 8, 10}, { 7, 12}, { 8, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 4, 6}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 5, 3}, + { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 19, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 12, 3}, { 1, 13}, /* Row 103 */ + { 1, 12}, { 4, 10}, { 8, 12}, { 7, 10}, { 7, 12}, { 7, 10}, { 9, 12}, { 4, 10}, + { 1, 12}, { 5, 6}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 6, 6}, + { 1, 5}, { 3, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 20, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 13, 3}, { 1, 11}, /* Row 104 */ + { 5, 10}, { 7, 12}, { 7, 10}, { 7, 12}, { 7, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 6, 6}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, { 2, 3}, + { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 21, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 13, 3}, { 1, 13}, /* Row 105 */ + { 1, 12}, { 4, 10}, { 8, 12}, { 6, 10}, { 7, 12}, { 6, 10}, { 9, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 7, 6}, + { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 22, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 14, 3}, { 1, 11}, /* Row 106 */ + { 5, 10}, { 7, 12}, { 6, 10}, { 7, 12}, { 6, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, { 6, 6}, + { 1, 18}, { 1, 5}, { 1, 3}, { 1, 4}, { 23, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 14, 3}, { 1, 13}, /* Row 107 */ + { 1, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 7, 12}, { 5, 10}, { 9, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 1, 3}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 3}, { 1, 4}, { 24, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 15, 3}, { 1, 11}, /* Row 108 */ + { 5, 10}, { 7, 12}, { 5, 10}, { 7, 12}, { 5, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 2, 3}, { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 5, 6}, { 1, 20}, { 1, 1}, { 25, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 15, 3}, { 1, 13}, /* Row 109 */ + { 1, 12}, { 4, 10}, { 8, 12}, { 4, 10}, { 7, 12}, { 4, 10}, { 9, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 3, 3}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 4, 6}, { 1, 20}, { 2, 2}, { 25, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 16, 3}, { 1, 11}, /* Row 110 */ + { 5, 10}, { 7, 12}, { 4, 10}, { 7, 12}, { 4, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 4, 3}, { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 2, 6}, { 1, 20}, { 3, 2}, { 1, 17}, { 24, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 16, 3}, { 1, 13}, /* Row 111 */ + { 1, 12}, { 4, 10}, { 8, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 9, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 5, 3}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 1, 21}, { 1, 20}, { 5, 2}, { 24, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 17, 3}, { 1, 11}, /* Row 112 */ + { 5, 10}, { 7, 12}, { 3, 10}, { 7, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 6, 3}, { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 14}, + { 6, 2}, { 1, 17}, { 23, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 17, 3}, { 1, 13}, /* Row 113 */ + { 1, 12}, { 4, 10}, { 8, 12}, { 2, 10}, { 7, 12}, { 2, 10}, { 9, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 7, 3}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 1, 18}, { 6, 2}, { 23, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 18, 3}, { 1, 11}, /* Row 114 */ + { 5, 10}, { 7, 12}, { 2, 10}, { 7, 12}, { 2, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 8, 3}, { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 14}, + { 6, 2}, { 1, 17}, { 22, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 18, 3}, { 1, 13}, /* Row 115 */ + { 1, 12}, { 4, 10}, { 8, 12}, { 1, 10}, { 7, 12}, { 1, 10}, { 9, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 9, 3}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 1, 18}, { 6, 2}, { 22, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 6}, { 19, 3}, { 1, 11}, /* Row 116 */ + { 5, 10}, { 7, 12}, { 1, 10}, { 7, 12}, { 1, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 10, 3}, { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 14}, + { 6, 2}, { 1, 17}, { 21, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 1, 18}, { 6, 6}, { 19, 3}, /* Row 117 */ + { 1, 13}, { 1, 12}, { 4, 10}, { 24, 12}, { 4, 10}, { 1, 12}, { 7, 6}, { 1, 5}, + { 11, 3}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, { 6, 2}, + { 21, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 1, 2}, { 1, 20}, { 5, 6}, /* Row 118 */ + { 20, 3}, { 1, 11}, { 5, 10}, { 22, 12}, { 5, 10}, { 1, 11}, { 7, 6}, { 12, 3}, + { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, + { 20, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 2, 2}, { 1, 20}, { 5, 6}, /* Row 119 */ + { 19, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 22, 12}, { 4, 10}, { 1, 12}, { 7, 6}, + { 1, 5}, { 13, 3}, { 1, 11}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, + { 6, 2}, { 20, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 3, 2}, { 1, 20}, { 3, 6}, /* Row 120 */ + { 1, 3}, { 1, 6}, { 19, 3}, { 1, 11}, { 5, 10}, { 20, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 14, 3}, { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, { 5, 10}, { 1, 14}, + { 6, 2}, { 1, 17}, { 19, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 4, 2}, { 1, 20}, { 2, 6}, /* Row 121 */ + { 2, 3}, { 1, 6}, { 18, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 20, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 14, 3}, { 1, 7}, { 1, 25}, { 4, 10}, { 8, 12}, + { 4, 10}, { 1, 12}, { 1, 18}, { 6, 2}, { 19, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 5, 2}, { 1, 20}, { 1, 6}, /* Row 122 */ + { 3, 3}, { 1, 6}, { 18, 3}, { 1, 11}, { 5, 10}, { 18, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 14, 3}, { 1, 7}, { 1, 2}, { 1, 13}, { 1, 12}, { 3, 10}, { 8, 12}, + { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, { 18, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 6, 2}, { 1, 20}, { 4, 3}, /* Row 123 */ + { 1, 6}, { 17, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 18, 12}, { 4, 10}, { 1, 12}, + { 7, 6}, { 1, 5}, { 13, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 20}, + { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, { 6, 2}, { 18, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 1, 0}, { 4, 3}, /* Row 124 */ + { 1, 6}, { 17, 3}, { 1, 11}, { 5, 10}, { 16, 12}, { 5, 10}, { 1, 11}, { 7, 6}, + { 13, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 1, 17}, { 4, 10}, + { 8, 12}, { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, { 17, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 1, 0}, { 1, 4}, /* Row 125 */ + { 4, 3}, { 1, 6}, { 16, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 16, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 12, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 2, 0}, { 1, 9}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, + { 6, 2}, { 17, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 2, 0}, { 1, 4}, /* Row 126 */ + { 4, 3}, { 1, 6}, { 16, 3}, { 1, 11}, { 5, 10}, { 14, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 12, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 4, 0}, + { 4, 10}, { 8, 12}, { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, { 16, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 3, 0}, { 1, 4}, /* Row 127 */ + { 4, 3}, { 1, 6}, { 15, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 14, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 11, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 5, 0}, { 1, 9}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, + { 6, 2}, { 16, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 4, 0}, { 1, 4}, /* Row 128 */ + { 4, 3}, { 1, 6}, { 15, 3}, { 1, 11}, { 5, 10}, { 12, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 11, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 7, 0}, + { 4, 10}, { 8, 12}, { 5, 10}, { 1, 14}, { 6, 2}, { 1, 17}, { 15, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 5, 0}, { 1, 4}, /* Row 129 */ + { 4, 3}, { 1, 6}, { 14, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 12, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 10, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 8, 0}, { 1, 9}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 12}, { 1, 18}, + { 6, 2}, { 15, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 6, 0}, { 1, 4}, /* Row 130 */ + { 4, 3}, { 1, 6}, { 14, 3}, { 1, 11}, { 5, 10}, { 10, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 10, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 10, 0}, + { 4, 10}, { 8, 12}, { 5, 10}, { 1, 14}, { 6, 2}, { 1, 26}, { 14, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 7, 0}, { 1, 4}, /* Row 131 */ + { 4, 3}, { 1, 6}, { 13, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 10, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 9, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 11, 0}, { 1, 9}, { 4, 10}, { 8, 12}, { 4, 10}, { 1, 14}, { 6, 2}, + { 1, 17}, { 14, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 8, 0}, { 1, 4}, /* Row 132 */ + { 4, 3}, { 1, 6}, { 13, 3}, { 1, 11}, { 5, 10}, { 8, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 9, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 13, 0}, + { 4, 10}, { 8, 12}, { 4, 10}, { 1, 14}, { 7, 2}, { 14, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 9, 0}, { 1, 4}, /* Row 133 */ + { 4, 3}, { 1, 6}, { 12, 3}, { 1, 13}, { 1, 12}, { 4, 10}, { 8, 12}, { 4, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 8, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 14, 0}, { 1, 9}, { 4, 10}, { 7, 12}, { 3, 10}, { 1, 12}, { 1, 19}, + { 7, 2}, { 1, 26}, { 13, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 10, 0}, { 1, 4}, /* Row 134 */ + { 4, 3}, { 1, 6}, { 12, 3}, { 1, 11}, { 5, 10}, { 6, 12}, { 5, 10}, { 1, 11}, + { 7, 6}, { 8, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 16, 0}, + { 4, 10}, { 6, 12}, { 4, 10}, { 1, 12}, { 8, 2}, { 1, 17}, { 13, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 11, 0}, { 1, 4}, /* Row 135 */ + { 4, 3}, { 1, 6}, { 11, 3}, { 1, 13}, { 1, 12}, { 5, 10}, { 4, 12}, { 5, 10}, + { 1, 12}, { 7, 6}, { 1, 5}, { 7, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, + { 1, 4}, { 17, 0}, { 1, 9}, { 4, 10}, { 4, 12}, { 5, 10}, { 1, 14}, { 8, 2}, + { 1, 17}, { 13, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 12, 0}, { 1, 4}, /* Row 136 */ + { 4, 3}, { 1, 6}, { 11, 3}, { 1, 11}, { 14, 10}, { 1, 11}, { 7, 6}, { 7, 3}, + { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 19, 0}, { 12, 10}, { 1, 12}, + { 1, 18}, { 8, 2}, { 1, 1}, { 13, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 13, 0}, { 1, 4}, /* Row 137 */ + { 4, 3}, { 1, 6}, { 10, 3}, { 1, 13}, { 1, 12}, { 12, 10}, { 1, 12}, { 7, 6}, + { 1, 5}, { 6, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 20, 0}, + { 1, 9}, { 10, 10}, { 1, 12}, { 10, 2}, { 14, 0}, + { 18, 0}, { 4, 10}, { 8, 12}, { 3, 10}, { 1, 12}, { 7, 2}, { 14, 0}, { 1, 4}, /* Row 138 */ + { 4, 3}, { 1, 6}, { 10, 3}, { 1, 11}, { 12, 10}, { 1, 11}, { 7, 6}, { 6, 3}, + { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 22, 0}, { 9, 10}, { 1, 12}, + { 10, 2}, { 1, 17}, { 14, 0}, + { 18, 0}, { 4, 10}, { 12, 12}, { 7, 2}, { 15, 0}, { 1, 4}, { 4, 3}, { 1, 6}, /* Row 139 */ + { 9, 3}, { 1, 5}, { 1, 15}, { 10, 10}, { 1, 15}, { 7, 6}, { 1, 5}, { 5, 3}, + { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 23, 0}, { 1, 17}, { 1, 14}, + { 5, 10}, { 1, 12}, { 1, 10}, { 1, 19}, { 10, 2}, { 15, 0}, + { 25, 0}, { 1, 20}, { 4, 18}, { 11, 2}, { 16, 0}, { 1, 4}, { 4, 3}, { 1, 6}, /* Row 140 */ + { 9, 3}, { 1, 5}, { 1, 11}, { 1, 12}, { 6, 10}, { 1, 12}, { 1, 11}, { 8, 6}, + { 5, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 27, 0}, { 2, 9}, + { 1, 19}, { 1, 14}, { 1, 18}, { 11, 2}, { 1, 17}, { 15, 0}, + { 25, 0}, { 16, 2}, { 17, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 10, 3}, { 1, 13}, /* Row 141 */ + { 1, 11}, { 4, 12}, { 1, 11}, { 9, 6}, { 5, 3}, { 1, 7}, { 1, 2}, { 1, 5}, + { 1, 3}, { 1, 4}, { 30, 0}, { 1, 1}, { 13, 2}, { 16, 0}, + { 25, 0}, { 16, 2}, { 18, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 11, 3}, { 1, 5}, /* Row 142 */ + { 1, 13}, { 11, 6}, { 5, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, + { 32, 0}, { 1, 17}, { 11, 2}, { 17, 0}, + { 25, 0}, { 16, 2}, { 19, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 13, 3}, { 1, 5}, /* Row 143 */ + { 7, 6}, { 6, 3}, { 1, 7}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 34, 0}, + { 10, 2}, { 18, 0}, + { 25, 0}, { 16, 2}, { 20, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 25, 3}, { 1, 7}, /* Row 144 */ + { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 35, 0}, { 1, 1}, { 7, 2}, { 1, 17}, + { 19, 0}, + { 25, 0}, { 16, 2}, { 21, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 23, 3}, { 1, 7}, /* Row 145 */ + { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 64, 0}, + { 25, 0}, { 16, 2}, { 22, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 21, 3}, { 1, 7}, /* Row 146 */ + { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 65, 0}, + { 64, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 19, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 147 */ + { 1, 3}, { 1, 4}, { 66, 0}, + { 65, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 17, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 148 */ + { 1, 3}, { 1, 4}, { 67, 0}, + { 66, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 15, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 149 */ + { 1, 3}, { 1, 4}, { 68, 0}, + { 67, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 13, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 150 */ + { 1, 3}, { 1, 4}, { 69, 0}, + { 68, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 11, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 151 */ + { 1, 3}, { 1, 4}, { 70, 0}, + { 69, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 9, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 152 */ + { 1, 3}, { 1, 4}, { 71, 0}, + { 70, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 7, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 153 */ + { 1, 3}, { 1, 4}, { 72, 0}, + { 71, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 5, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 154 */ + { 1, 3}, { 1, 4}, { 73, 0}, + { 72, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 3, 3}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 155 */ + { 1, 3}, { 1, 4}, { 74, 0}, + { 73, 0}, { 1, 4}, { 4, 3}, { 1, 6}, { 1, 5}, { 1, 7}, { 1, 2}, { 1, 5}, /* Row 156 */ + { 1, 3}, { 1, 4}, { 75, 0}, + { 74, 0}, { 1, 4}, { 5, 3}, { 1, 2}, { 1, 5}, { 1, 3}, { 1, 4}, { 76, 0}, /* Row 157 */ + { 75, 0}, { 1, 4}, { 2, 3}, { 1, 5}, { 1, 20}, { 1, 5}, { 1, 3}, { 1, 4}, /* Row 158 */ + { 77, 0}, + { 76, 0}, { 1, 4}, { 4, 3}, { 1, 4}, { 78, 0} /* Row 159 */ +}; + +# endif +#else +# error "Unsupport pixel format" +#endif + +/******************************************************************************************** + * Public Data + ********************************************************************************************/ + +/******************************************************************************************** + * Private Functions + ********************************************************************************************/ + +/******************************************************************************************** + * Public Functions + ********************************************************************************************/ + +/******************************************************************************************** + * Name:nximage_bgcolor + * + * Description: + * Return the color of the background. In this case, we know that this is the first + * encoded color in the look-up table. + * + ********************************************************************************************/ + +nxgl_mxpixel_t nximage_bgcolor(void) +{ + return g_lut[0]; +} + +/******************************************************************************************** + * Name:nximage_avgcolor + * + * Description: + * Take the average of two pixel RGB values. + * + ********************************************************************************************/ + +nxgl_mxpixel_t nximage_avgcolor(nxgl_mxpixel_t color1, nxgl_mxpixel_t color2) +{ +#ifdef CONFIG_EXAMPLES_NXIMAGE_GREYSCALE + + return (nxgl_mxpixel_t)(((unsigned int)color1 + (unsigned int)color2) >> 1); + +#else /* CONFIG_EXAMPLES_NXIMAGE_GREYSCALE */ + unsigned int r1; + unsigned int g1; + unsigned int b1; + unsigned int r2; + unsigned int g2; + unsigned int b2; + +#if CONFIG_EXAMPLES_NXIMAGE_BPP == 24 + + /* RGB24 (8-8-8) Colors */ + + /* Demultiplex */ + + r1 = (color1 >> 16) & 0xff; /* 8-bit */ + g1 = (color1 >> 8) & 0xff; /* 8-bit */ + b1 = color1 & 0xff; /* 8-bit */ + + r2 = (color2 >> 16) & 0xff; /* 8-bit */ + g2 = (color2 >> 8) & 0xff; /* 8-bit */ + b2 = color2 & 0xff; /* 8-bit */ + + /* Average */ + + r1 = (r1 + r2 + 1) >> 1; /* 8-bit */ + g1 = (g1 + g2 + 1) >> 1; /* 8-bit */ + b1 = (b1 + b2 + 1) >> 1; /* 8-bit */ + + /* Clip */ + + if (r1 > 0xff) + { + r1 = 0xff; + } + + if (g1 > 0xff) + { + g1 = 0xff; + } + + if (b1 > 0xff) + { + b1 = 0xff; + } + + /* Multiplex */ + + color1 = r1 << 16 | g1 << 8 | b1; + +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 16 + + /* RGB16 (565) Colors */ + + /* Demultiplex */ + + r1 = (color1 >> 11) & 0x1f; /* 5-bit */ + g1 = (color1 >> 5) & 0x3f; /* 6-bit */ + b1 = color1 & 0x1f; /* 5-bit */ + + r2 = (color2 >> 11) & 0x1f; /* 5-bit */ + g2 = (color2 >> 5) & 0x3f; /* 6-bit */ + b2 = color2 & 0x1f; /* 5-bit */ + + /* Average */ + + r1 = (r1 + r2 + 1) >> 1; /* 5-bit */ + g1 = (g1 + g2 + 1) >> 1; /* 6-bit */ + b1 = (b1 + b2 + 1) >> 1; /* 5-bit */ + + /* Clip */ + + if (r1 > 0x1f) + { + r1 = 0x1f; + } + + if (g1 > 0x3f) + { + g1 = 0x3f; + } + + if (b1 > 0x1f) + { + b1 = 0x1f; + } + + /* Multiplex */ + + color1 = r1 << 11 | g1 << 5 | b1; + +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 8 + + /* RGB8 (332) Colors */ + + /* Demultiplex */ + + r1 = (color1 >> 5) & 0x07; /* 3-bit */ + g1 = (color1 >> 2) & 0x07; /* 3-bit */ + b1 = color1 & 0x03; /* 2-bit */ + + r2 = (color2 >> 5) & 0x07; /* 3-bit */ + g2 = (color2 >> 2) & 0x07; /* 3-bit */ + b2 = color2 & 0x03; /* 2-bit */ + + /* Average */ + + r1 = (r1 + r2 + 1) >> 1; /* 3-bit */ + g1 = (g1 + g2 + 1) >> 1; /* 3-bit */ + b1 = (b1 + b2 + 1) >> 1; /* 2-bit */ + + /* RGB24 (8-8-8) Colors */ + + /* Clip */ + + if (r1 > 0x07) + { + r1 = 0x07; + } + + if (g1 > 0x07) + { + g1 = 0x07; + } + + if (b1 > 0x03) + { + b1 = 0x03; + } + + /* Multiplex */ + + color1 = r1 << 5 | g1 << 2 | b1; + +#else +# error "Unsupport pixel format" +#endif + + return color1; +#endif /* CONFIG_EXAMPLES_NXIMAGE_GREYSCALE */ +} + +/******************************************************************************************** + * Name: nximage_blitrow + * + * Description: + * Return the next properly scaled row from the image. + * + ********************************************************************************************/ + +void nximage_blitrow(FAR nxgl_mxpixel_t *run, FAR const void **state) +{ + FAR const struct pix_run_s *pos = *(FAR const struct pix_run_s **)state; + unsigned int width; +#if defined(CONFIG_EXAMPLES_NXIMAGE_XSCALEp5) || defined(CONFIG_EXAMPLES_NXIMAGE_XSCALE1p5) + unsigned int nhalfpixels; + nxgl_mxpixel_t last; +#endif + unsigned int nrun; + nxgl_mxpixel_t color; + + /* NULL positional data means to start over */ + + if (!pos) + { + pos = g_nuttx; + } + + /* Process each run-length encoded pixel in the image */ + +#if defined(CONFIG_EXAMPLES_NXIMAGE_XSCALEp5) || defined(CONFIG_EXAMPLES_NXIMAGE_XSCALE1p5) + nhalfpixels = 0; + last = nximage_bgcolor(); +#endif + + for (width = 0; width < SCALED_WIDTH; pos++) + { + nrun = (unsigned int)pos->npix; + color = g_lut[pos->code]; + +#if defined(CONFIG_EXAMPLES_NXIMAGE_XSCALEp5) || defined(CONFIG_EXAMPLES_NXIMAGE_XSCALE1p5) + nhalfpixels += nrun & 1; +#ifdef CONFIG_EXAMPLES_NXIMAGE_XSCALEp5 + nrum >>= 1; +#else + nrun = nrun + (nrun >> 1); +#endif + if (nhalfpixels > 1) + { + *run++ = nximage_avgcolor(color, last); + nhalfpixels -= 2; + width++; + } + last = color; +#elif defined(CONFIG_EXAMPLES_NXIMAGE_XSCALE2p0) + nrun <<= 1; +#endif + width += nrun; + while (nrun-- > 0) + { + *run++ = color; + } + } + ASSERT(width == SCALED_WIDTH); + + /* Save the start of the next row and return success */ + + *state = (FAR const void *)pos; +} diff --git a/apps/examples/nximage/nximage_bkgd.c b/apps/examples/nximage/nximage_bkgd.c new file mode 100755 index 000000000..e724b3a31 --- /dev/null +++ b/apps/examples/nximage/nximage_bkgd.c @@ -0,0 +1,397 @@ +/**************************************************************************** + * examples/nximage/nximage_bkgd.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <semaphore.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxglib.h> +#include <nuttx/nx/nxfonts.h> + +#include "nximage.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Select renderer -- Some additional logic would be required to support + * pixel depths that are not directly addressable (1,2,4, and 24). + */ + +#if CONFIG_EXAMPLES_NXIMAGE_BPP == 1 +# define RENDERER nxf_convert_1bpp +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 2 +# define RENDERER nxf_convert_2bpp +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 4 +# define RENDERER nxf_convert_4bpp +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 8 +# define RENDERER nxf_convert_8bpp +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 16 +# define RENDERER nxf_convert_16bpp +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 24 +# define RENDERER nxf_convert_24bpp +#elif CONFIG_EXAMPLES_NXIMAGE_BPP == 32 +# define RENDERER nxf_convert_32bpp +#else +# error "Unsupported CONFIG_EXAMPLES_NXIMAGE_BPP" +#endif + +/* Vertical scaling */ + +#if defined(CONFIG_EXAMPLES_NXIMAGE_YSCALEp5) + +/* Read two rows, output one averaged row */ + +#define NINPUT_ROWS 2 +#define NOUTPUT_ROWS 1 + +#elif defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5) +/* Read two rows, output three rows */ + +#define NINPUT_ROWS 2 +#define NOUTPUT_ROWS 3 + +#elif defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE2p0) +/* Read one row, output two rows */ + +#define NINPUT_ROWS 1 +#define NOUTPUT_ROWS 2 + +#else +/* Read one rows, output one or two rows */ + +#define NINPUT_ROWS 1 +#define NOUTPUT_ROWS 1 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nximage_run_t +{ + nxgl_mxpixel_t run[SCALED_WIDTH]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void nximage_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool more, FAR void *arg); +static void nximage_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg); +#ifdef CONFIG_NX_MOUSE +static void nximage_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg); +#endif + +#ifdef CONFIG_NX_KBD +static void nximage_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_hello[] = "Hello, World!"; + +/* Read one or two rows, output one tow or three rows */ + +static struct nximage_run_t g_runs[NINPUT_ROWS]; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Background window call table */ + +const struct nx_callback_s g_bgcb = +{ + nximage_redraw, /* redraw */ + nximage_position /* position */ +#ifdef CONFIG_NX_MOUSE + , nximage_mousein /* mousein */ +#endif +#ifdef CONFIG_NX_KBD + , nximage_kbdin /* my kbdin */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nximage_redraw + * + * Description: + * NX re-draw handler + * + ****************************************************************************/ + +static void nximage_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool more, FAR void *arg) +{ + gvdbg("hwnd=%p rect={(%d,%d),(%d,%d)} more=%s\n", + hwnd, rect->pt1.x, rect->pt1.y, rect->pt2.x, rect->pt2.y, + more ? "true" : "false"); +} + +/**************************************************************************** + * Name: nximage_position + * + * Description: + * NX position change handler + * + ****************************************************************************/ + +static void nximage_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg) +{ + /* Report the position */ + + gvdbg("hwnd=%p size=(%d,%d) pos=(%d,%d) bounds={(%d,%d),(%d,%d)}\n", + hwnd, size->w, size->h, pos->x, pos->y, + bounds->pt1.x, bounds->pt1.y, bounds->pt2.x, bounds->pt2.y); + + /* Have we picked off the window bounds yet? */ + + if (!g_nximage.havepos) + { + /* Save the background window handle */ + + g_nximage.hbkgd = hwnd; + + /* Save the window limits */ + + g_nximage.xres = bounds->pt2.x + 1; + g_nximage.yres = bounds->pt2.y + 1; + + g_nximage.havepos = true; + sem_post(&g_nximage.sem); + gvdbg("Have xres=%d yres=%d\n", g_nximage.xres, g_nximage.yres); + } +} + +/**************************************************************************** + * Name: nximage_mousein + * + * Description: + * NX mouse input handler + * + ****************************************************************************/ + +#ifdef CONFIG_NX_MOUSE +static void nximage_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg) +{ + message("nximage_mousein: hwnd=%p pos=(%d,%d) button=%02x\n", + hwnd, pos->x, pos->y, buttons); +} +#endif + +/**************************************************************************** + * Name: nximage_kbdin + * + * Description: + * NX keyboard input handler + * + ****************************************************************************/ + +#ifdef CONFIG_NX_KBD +static void nximage_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg) +{ + gvdbg("hwnd=%p nch=%d\n", hwnd, nch); + + /* In this example, there is no keyboard so a keyboard event is not + * expected. + */ + + message("nximage_kbdin: Unexpected keyboard callback\n"); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nximage_image + * + * Description: + * Put the NuttX logo in the center of the display. + * + ****************************************************************************/ + +void nximage_image(NXWINDOW hwnd) +{ + FAR const void *state = NULL; + FAR struct nxgl_point_s pos; + FAR struct nxgl_rect_s dest; + FAR const void *src[CONFIG_NX_NPLANES]; + nxgl_coord_t row; + int ret; +#if defined(CONFIG_EXAMPLES_NXIMAGE_YSCALEp5) || defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5) + int i; +#endif + + /* Center the image. Note: these may extend off the display. */ + + pos.x = (g_nximage.xres - SCALED_WIDTH) / 2; + pos.y = (g_nximage.yres - SCALED_HEIGHT) / 2; + + /* Set up the invariant part of the destination bounding box */ + + dest.pt1.x = pos.x; + dest.pt2.x = pos.x + SCALED_WIDTH - 1; + + /* Now output the rows */ + + for (row = 0; row < IMAGE_HEIGHT; row += NINPUT_ROWS) + { + /* Read input row(s) */ + + nximage_blitrow(g_runs[0].run, &state); +#if NINPUT_ROWS > 1 + nximage_blitrow(g_runs[1].run, &state); +#endif + + /* Output rows before averaging */ + +#if defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5) || defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE2p0) + + /* Output row[0] */ + + dest.pt1.y = pos.y; + dest.pt2.y = pos.y; + + src[0] = (FAR const void *)g_runs[0].run; +#if CONFIG_NX_NPLANES > 1 +# warning "More logic is needed for the case where CONFIG_NX_PLANES > 1" +#endif + ret = nx_bitmap((NXWINDOW)hwnd, &dest, src, &pos, SCALED_WIDTH*sizeof(nxgl_mxpixel_t)); + if (ret < 0) + { + message("nximage_image: nx_bitmapwindow failed: %d\n", errno); + } + + /* Increment the vertical position */ + + pos.y++; +#endif + + /* Perform averaging */ + +#if defined(CONFIG_EXAMPLES_NXIMAGE_YSCALEp5) || defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5) + + /* Average row[0] and row[1], output results in row[0] */ + + for (i = 0; i < SCALED_WIDTH; i++) + { + /* Only average if the corresponding pixels in each row differ */ + + nxgl_mxpixel_t pix0 = g_runs[0].run[i]; + nxgl_mxpixel_t pix1 = g_runs[1].run[i]; + if (pix0 != pix1) + { + g_runs[0].run[i] = nximage_avgcolor(pix0, pix1); + } + } + +#endif + + /* Output rows after averaging */ + + /* Output row[0] */ + + dest.pt1.y = pos.y; + dest.pt2.y = pos.y; + + src[0] = (FAR const void *)g_runs[0].run; +#if CONFIG_NX_NPLANES > 1 +# warning "More logic is needed for the case where CONFIG_NX_PLANES > 1" +#endif + ret = nx_bitmap((NXWINDOW)hwnd, &dest, src, &pos, SCALED_WIDTH*sizeof(nxgl_mxpixel_t)); + if (ret < 0) + { + message("nximage_image: nx_bitmapwindow failed: %d\n", errno); + } + + /* Increment the vertical position */ + + pos.y++; + +#if defined(CONFIG_EXAMPLES_NXIMAGE_YSCALE1p5) + + /* Output row[0] and row[1] */ + + dest.pt1.y = pos.y; + dest.pt2.y = pos.y; + + src[0] = (FAR const void *)g_runs[1].run; +#if CONFIG_NX_NPLANES > 1 +# warning "More logic is needed for the case where CONFIG_NX_PLANES > 1" +#endif + ret = nx_bitmap((NXWINDOW)hwnd, &dest, src, &pos, SCALED_WIDTH*sizeof(nxgl_mxpixel_t)); + if (ret < 0) + { + message("nximage_image: nx_bitmapwindow failed: %d\n", errno); + } + + /* Increment the vertical position */ + + pos.y++; +#endif + } +} diff --git a/apps/examples/nximage/nximage_main.c b/apps/examples/nximage/nximage_main.c new file mode 100755 index 000000000..3ddfb1c02 --- /dev/null +++ b/apps/examples/nximage/nximage_main.c @@ -0,0 +1,289 @@ +/**************************************************************************** + * examples/nximage/nximage_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <string.h> +#include <sched.h> +#include <pthread.h> +#include <errno.h> +#include <debug.h> + +#ifdef CONFIG_NX_LCDDRIVER +# include <nuttx/lcd/lcd.h> +#else +# include <nuttx/fb.h> +#endif + +#include <nuttx/arch.h> +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxglib.h> +#include <nuttx/nx/nxfonts.h> + +#include "nximage.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ +/* If not specified, assume that the hardware supports one video plane */ + +#ifndef CONFIG_EXAMPLES_NXIMAGE_VPLANE +# define CONFIG_EXAMPLES_NXIMAGE_VPLANE 0 +#endif + +/* If not specified, assume that the hardware supports one LCD device */ + +#ifndef CONFIG_EXAMPLES_NXIMAGE_DEVNO +# define CONFIG_EXAMPLES_NXIMAGE_DEVNO 0 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct nximage_data_s g_nximage = +{ + NULL, /* hnx */ + NULL, /* hbkgd */ + 0, /* xres */ + 0, /* yres */ + false, /* havpos */ + { 0 }, /* sem */ + NXEXIT_SUCCESS /* exit code */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nximage_initialize + * + * Description: + * Initialize the LCD or framebuffer device (single user mode only), then + * open NX. + * + ****************************************************************************/ + +static inline int nximage_initialize(void) +{ + FAR NX_DRIVERTYPE *dev; + +#if defined(CONFIG_EXAMPLES_NXIMAGE_EXTERNINIT) + /* Use external graphics driver initialization */ + + message("nximage_initialize: Initializing external graphics device\n"); + dev = up_nxdrvinit(CONFIG_EXAMPLES_NXIMAGE_DEVNO); + if (!dev) + { + message("nximage_initialize: up_nxdrvinit failed, devno=%d\n", + CONFIG_EXAMPLES_NXIMAGE_DEVNO); + g_nximage.code = NXEXIT_EXTINITIALIZE; + return ERROR; + } + +#elif defined(CONFIG_NX_LCDDRIVER) + int ret; + + /* Initialize the LCD device */ + + message("nximage_initialize: Initializing LCD\n"); + ret = up_lcdinitialize(); + if (ret < 0) + { + message("nximage_initialize: up_lcdinitialize failed: %d\n", -ret); + g_nximage.code = NXEXIT_LCDINITIALIZE; + return ERROR; + } + + /* Get the device instance */ + + dev = up_lcdgetdev(CONFIG_EXAMPLES_NXIMAGE_DEVNO); + if (!dev) + { + message("nximage_initialize: up_lcdgetdev failed, devno=%d\n", CONFIG_EXAMPLES_NXIMAGE_DEVNO); + g_nximage.code = NXEXIT_LCDGETDEV; + return ERROR; + } + + /* Turn the LCD on at 75% power */ + + (void)dev->setpower(dev, ((3*CONFIG_LCD_MAXPOWER + 3)/4)); +#else + int ret; + + /* Initialize the frame buffer device */ + + message("nximage_initialize: Initializing framebuffer\n"); + ret = up_fbinitialize(); + if (ret < 0) + { + message("nximage_initialize: up_fbinitialize failed: %d\n", -ret); + g_nximage.code = NXEXIT_FBINITIALIZE; + return ERROR; + } + + dev = up_fbgetvplane(CONFIG_EXAMPLES_NXIMAGE_VPLANE); + if (!dev) + { + message("nximage_initialize: up_fbgetvplane failed, vplane=%d\n", CONFIG_EXAMPLES_NXIMAGE_VPLANE); + g_nximage.code = NXEXIT_FBGETVPLANE; + return ERROR; + } +#endif + + /* Then open NX */ + + message("nximage_initialize: Open NX\n"); + g_nximage.hnx = nx_open(dev); + if (!g_nximage.hnx) + { + message("nximage_initialize: nx_open failed: %d\n", errno); + g_nximage.code = NXEXIT_NXOPEN; + return ERROR; + } + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start/nximage_main + * + * Description: + * Main entry pointer. Configures the basic display resources. + * + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXIMAGE_BUILTIN +# define MAIN_NAME nximage_main +# define MAIN_NAME_STRING "nximage_main" +#else +# define MAIN_NAME user_start +# define MAIN_NAME_STRING "user_start" +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + nxgl_mxpixel_t color; + int ret; + + /* Initialize NX */ + + ret = nximage_initialize(); + message(MAIN_NAME_STRING ": NX handle=%p\n", g_nximage.hnx); + if (!g_nximage.hnx || ret < 0) + { + message(MAIN_NAME_STRING ": Failed to get NX handle: %d\n", errno); + g_nximage.code = NXEXIT_NXOPEN; + goto errout; + } + + /* Set the background to the configured background color */ + + color = nximage_bgcolor(); + message(MAIN_NAME_STRING ": Set background color=%d\n", color); + + ret = nx_setbgcolor(g_nximage.hnx, &color); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_setbgcolor failed: %d\n", errno); + g_nximage.code = NXEXIT_NXSETBGCOLOR; + goto errout_with_nx; + } + + /* Get the background window */ + + ret = nx_requestbkgd(g_nximage.hnx, &g_bgcb, NULL); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_setbgcolor failed: %d\n", errno); + g_nximage.code = NXEXIT_NXREQUESTBKGD; + goto errout_with_nx; + } + + /* Wait until we have the screen resolution. We'll have this immediately + * unless we are dealing with the NX server. + */ + + while (!g_nximage.havepos) + { + (void)sem_wait(&g_nximage.sem); + } + message(MAIN_NAME_STRING ": Screen resolution (%d,%d)\n", g_nximage.xres, g_nximage.yres); + + /* Now, put up the NuttX logo. */ + + nximage_image(g_nximage.hbkgd); + + /* Release background */ + + (void)nx_releasebkgd(g_nximage.hbkgd); + + /* Close NX */ + +errout_with_nx: + message(MAIN_NAME_STRING ": Close NX\n"); + nx_close(g_nximage.hnx); +errout: + return g_nximage.code; +} diff --git a/apps/examples/nxlines/Makefile b/apps/examples/nxlines/Makefile new file mode 100644 index 000000000..0c865c42d --- /dev/null +++ b/apps/examples/nxlines/Makefile @@ -0,0 +1,105 @@ +############################################################################ +# apps/examples/nxlines/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttX NX Graphics Example. + +ASRCS = +CSRCS = nxlines_main.c nxlines_bkgd.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# NXLINES built-in application info + +APPNAME = nxlines +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_NXLINES_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/nxlines/nxlines.h b/apps/examples/nxlines/nxlines.h new file mode 100644 index 000000000..fb91f23a3 --- /dev/null +++ b/apps/examples/nxlines/nxlines.h @@ -0,0 +1,197 @@ +/**************************************************************************** + * examples/nxlines/nxlines.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_NXLINES_NXLINES_H +#define __APPS_EXAMPLES_NXLINES_NXLINES_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <semaphore.h> + +#include <nuttx/nx/nxglib.h> +#include <nuttx/nx/nx.h> +#include <nuttx/rgbcolors.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_NX +# error "NX is not enabled (CONFIG_NX)" +#endif + +#ifndef CONFIG_EXAMPLES_NXLINES_VPLANE +# define CONFIG_EXAMPLES_NXLINES_VPLANE 0 +#endif + +#ifndef CONFIG_EXAMPLES_NXLINES_BPP +# define CONFIG_EXAMPLES_NXLINES_BPP 16 +#endif + +#ifndef CONFIG_EXAMPLES_NXLINES_BGCOLOR +# if CONFIG_EXAMPLES_NXLINES_BPP == 24 || CONFIG_EXAMPLES_NXLINES_BPP == 32 +# define CONFIG_EXAMPLES_NXLINES_BGCOLOR RGB24_DARKGREEN +# elif CONFIG_EXAMPLES_NXLINES_BPP == 16 +# define CONFIG_EXAMPLES_NXLINES_BGCOLOR RGB16_DARKGREEN +# else +# define CONFIG_EXAMPLES_NXLINES_BGCOLOR RGB8_DARKGREEN +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NXLINES_LINEWIDTH +# define CONFIG_EXAMPLES_NXLINES_LINEWIDTH 16 +#endif + +#ifndef CONFIG_EXAMPLES_NXLINES_LINECOLOR +# if CONFIG_EXAMPLES_NXLINES_BPP == 24 || CONFIG_EXAMPLES_NXLINES_BPP == 32 +# define CONFIG_EXAMPLES_NXLINES_LINECOLOR RGB24_YELLOW +# elif CONFIG_EXAMPLES_NXLINES_BPP == 16 +# define CONFIG_EXAMPLES_NXLINES_LINECOLOR RGB16_YELLOW +# else +# define CONFIG_EXAMPLES_NXLINES_LINECOLOR RGB8_YELLOW +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NXLINES_BORDERWIDTH +# define CONFIG_EXAMPLES_NXLINES_BORDERWIDTH 16 +#endif + +#ifndef CONFIG_EXAMPLES_NXLINES_BORDERCOLOR +# if CONFIG_EXAMPLES_NXLINES_BPP == 24 || CONFIG_EXAMPLES_NXLINES_BPP == 32 +# define CONFIG_EXAMPLES_NXLINES_BORDERCOLOR RGB24_YELLOW +# elif CONFIG_EXAMPLES_NXLINES_BPP == 16 +# define CONFIG_EXAMPLES_NXLINES_BORDERCOLOR RGB16_YELLOW +# else +# define CONFIG_EXAMPLES_NXLINES_BORDERCOLOR RGB8_YELLOW +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NXLINES_CIRCLECOLOR +# if CONFIG_EXAMPLES_NXLINES_BPP == 24 || CONFIG_EXAMPLES_NXLINES_BPP == 32 +# define CONFIG_EXAMPLES_NXLINES_CIRCLECOLOR RGB24_BEIGE +# elif CONFIG_EXAMPLES_NXLINES_BPP == 16 +# define CONFIG_EXAMPLES_NXLINES_CIRCLECOLOR RGB16_BEIGE +# else +# define CONFIG_EXAMPLES_NXLINES_CIRCLECOLOR RGB8_YELLOW +# endif +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum exitcode_e +{ + NXEXIT_SUCCESS = 0, + NXEXIT_EXTINITIALIZE, + NXEXIT_FBINITIALIZE, + NXEXIT_FBGETVPLANE, + NXEXIT_LCDINITIALIZE, + NXEXIT_LCDGETDEV, + NXEXIT_NXOPEN, + NXEXIT_NXREQUESTBKGD, + NXEXIT_NXSETBGCOLOR +}; + +struct nxlines_data_s +{ + /* The NX handles */ + + NXHANDLE hnx; + NXHANDLE hbkgd; + + /* The screen resolution */ + + nxgl_coord_t xres; + nxgl_coord_t yres; + + volatile bool havepos; + sem_t sem; + volatile int code; +}; + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/* NXLINES state data */ + +extern struct nxlines_data_s g_nxlines; + +/* NX callback vtables */ + +extern const struct nx_callback_s g_bgcb; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXLINES_EXTERNINIT +extern FAR NX_DRIVERTYPE *up_nxdrvinit(unsigned int devno); +#endif + +/* Background window interfaces */ + +extern void nxlines_test(NXWINDOW hwnd); + +#endif /* __APPS_EXAMPLES_NXLINES_NXLINES_H */ diff --git a/apps/examples/nxlines/nxlines_bkgd.c b/apps/examples/nxlines/nxlines_bkgd.c new file mode 100644 index 000000000..c9cbc921d --- /dev/null +++ b/apps/examples/nxlines/nxlines_bkgd.c @@ -0,0 +1,335 @@ +/**************************************************************************** + * examples/nxlines/nxlines_bkgd.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <debug.h> +#include <fixedmath.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxglib.h> + +#include "nxlines.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifndef MIN +# define MIN(a,b) (a < b ? a : b) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void nxlines_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool morem, FAR void *arg); +static void nxlines_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg); +#ifdef CONFIG_NX_MOUSE +static void nxlines_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg); +#endif + +#ifdef CONFIG_NX_KBD +static void nxlines_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Background window call table */ + +const struct nx_callback_s g_bgcb = +{ + nxlines_redraw, /* redraw */ + nxlines_position /* position */ +#ifdef CONFIG_NX_MOUSE + , nxlines_mousein /* mousein */ +#endif +#ifdef CONFIG_NX_KBD + , nxlines_kbdin /* my kbdin */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxlines_redraw + ****************************************************************************/ + +static void nxlines_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool more, FAR void *arg) +{ + gvdbg("hwnd=%p rect={(%d,%d),(%d,%d)} more=%s\n", + hwnd, rect->pt1.x, rect->pt1.y, rect->pt2.x, rect->pt2.y, + more ? "true" : "false"); +} + +/**************************************************************************** + * Name: nxlines_position + ****************************************************************************/ + +static void nxlines_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg) +{ + /* Report the position */ + + gvdbg("hwnd=%p size=(%d,%d) pos=(%d,%d) bounds={(%d,%d),(%d,%d)}\n", + hwnd, size->w, size->h, pos->x, pos->y, + bounds->pt1.x, bounds->pt1.y, bounds->pt2.x, bounds->pt2.y); + + /* Have we picked off the window bounds yet? */ + + if (!g_nxlines.havepos) + { + /* Save the background window handle */ + + g_nxlines.hbkgd = hwnd; + + /* Save the window limits */ + + g_nxlines.xres = bounds->pt2.x + 1; + g_nxlines.yres = bounds->pt2.y + 1; + + g_nxlines.havepos = true; + sem_post(&g_nxlines.sem); + gvdbg("Have xres=%d yres=%d\n", g_nxlines.xres, g_nxlines.yres); + } +} + +/**************************************************************************** + * Name: nxlines_mousein + ****************************************************************************/ + +#ifdef CONFIG_NX_MOUSE +static void nxlines_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg) +{ + message("nxlines_mousein: hwnd=%p pos=(%d,%d) button=%02x\n", + hwnd, pos->x, pos->y, buttons); +} +#endif + +/**************************************************************************** + * Name: nxlines_kbdin + ****************************************************************************/ + +#ifdef CONFIG_NX_KBD +static void nxlines_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg) +{ + gvdbg("hwnd=%p nch=%d\n", hwnd, nch); + + /* In this example, there is no keyboard so a keyboard event is not + * expected. + */ + + message("nxlines_kbdin: Unexpected keyboard callback\n"); +} +#endif + + /**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxlines_test + * + * Description: + * Print "Hello, World!" in the center of the display. + * + ****************************************************************************/ + +void nxlines_test(NXWINDOW hwnd) +{ + struct nxgl_point_s center; + struct nxgl_vector_s vector; + struct nxgl_vector_s previous; + nxgl_mxpixel_t color[CONFIG_NX_NPLANES]; + nxgl_coord_t maxradius; + nxgl_coord_t radius; + nxgl_coord_t halfx; + nxgl_coord_t halfy; + b16_t angle; + int ret; + + /* Get the maximum radius and center of the circle */ + + maxradius = MIN(g_nxlines.yres, g_nxlines.xres) >> 1; + center.x = g_nxlines.xres >> 1; + center.y = g_nxlines.yres >> 1; + + /* Draw a circular background */ + + radius = maxradius - ((CONFIG_EXAMPLES_NXLINES_BORDERWIDTH+1)/2); + color[0] = CONFIG_EXAMPLES_NXLINES_CIRCLECOLOR; + ret = nx_fillcircle((NXWINDOW)hwnd, ¢er, radius, color); + if (ret < 0) + { + message("nxlines_test: nx_fillcircle failed: %d\n", ret); + } + + /* Draw the circular border */ + + color[0] = CONFIG_EXAMPLES_NXLINES_BORDERCOLOR; + ret = nx_drawcircle((NXWINDOW)hwnd, ¢er, radius, + CONFIG_EXAMPLES_NXLINES_BORDERWIDTH, color); + if (ret < 0) + { + message("nxlines_test: nx_fillcircle failed: %d\n", ret); + } + + /* Back off the radius to account for the thickness of border line + * and with a big fudge factor that will (hopefully) prevent the corners + * of the lines from overwriting the border. This is overly complicated + * here because we don't assume anything about the screen resolution or + * the borderwidth or the line thickness (and there are certainly some + * smarter ways to do this). + */ + + if (maxradius > (CONFIG_EXAMPLES_NXLINES_BORDERWIDTH + 80)) + { + radius = maxradius - (CONFIG_EXAMPLES_NXLINES_BORDERWIDTH + 40); + } + else if (maxradius > (CONFIG_EXAMPLES_NXLINES_BORDERWIDTH + 60)) + { + radius = maxradius - (CONFIG_EXAMPLES_NXLINES_BORDERWIDTH + 30); + } + else if (maxradius > (CONFIG_EXAMPLES_NXLINES_BORDERWIDTH + 40)) + { + radius = maxradius - (CONFIG_EXAMPLES_NXLINES_BORDERWIDTH + 20); + } + else if (maxradius > (CONFIG_EXAMPLES_NXLINES_BORDERWIDTH + 20)) + { + radius = maxradius - (CONFIG_EXAMPLES_NXLINES_BORDERWIDTH + 10); + } + else + { + radius = maxradius - CONFIG_EXAMPLES_NXLINES_BORDERWIDTH; + } + + /* The loop, showing the line in various orientations */ + + angle = 0; + previous.pt1.x = center.x; + previous.pt1.y = center.y; + previous.pt2.x = center.x; + previous.pt2.y = center.y; + + for (;;) + { + /* Determine the position of the line on this pass */ + + halfx = b16toi(b16muli(b16sin(angle), radius)); + halfy = b16toi(b16muli(b16cos(angle), radius)); + + vector.pt1.x = center.x + halfx; + vector.pt1.y = center.y + halfy; + vector.pt2.x = center.x - halfx; + vector.pt2.y = center.y - halfy; + + message("Angle: %08x vector: (%d,%d)->(%d,%d)\n", + angle, vector.pt1.x, vector.pt1.y, vector.pt2.x, vector.pt2.y); + + /* Clear the previous line by overwriting it with the circle color */ + + color[0] = CONFIG_EXAMPLES_NXLINES_CIRCLECOLOR; + ret = nx_drawline((NXWINDOW)hwnd, &previous, CONFIG_EXAMPLES_NXLINES_LINEWIDTH, color); + if (ret < 0) + { + message("nxlines_test: nx_drawline failed clearing: %d\n", ret); + } + + /* Draw the new line */ + + color[0] = CONFIG_EXAMPLES_NXLINES_LINECOLOR; + ret = nx_drawline((NXWINDOW)hwnd, &vector, CONFIG_EXAMPLES_NXLINES_LINEWIDTH, color); + if (ret < 0) + { + message("nxlines_test: nx_drawline failed clearing: %d\n", ret); + } + + /* Set up for the next time through the loop then sleep for a bit. */ + + angle += b16PI / 16; /* 32 angular positions in full circle */ + + /* Check if we have gone all the way around */ + + if (angle > (31 * (2 * b16PI) / 32)) + { +#ifdef CONFIG_EXAMPLES_NXLINES_BUILTIN + /* If this example was built as an NSH add-on, then exit after we + * have gone all the way around once. + */ + + return; +#else + /* Wrap back to zero and continue with the test */ + + angle = 0; +#endif + } + + memcpy(&previous, &vector, sizeof(struct nxgl_vector_s)); + usleep(500*1000); + } +} diff --git a/apps/examples/nxlines/nxlines_main.c b/apps/examples/nxlines/nxlines_main.c new file mode 100644 index 000000000..c1485e0ef --- /dev/null +++ b/apps/examples/nxlines/nxlines_main.c @@ -0,0 +1,280 @@ +/**************************************************************************** + * examples/nxlines/nxlines_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <string.h> +#include <sched.h> +#include <errno.h> +#include <debug.h> + +#ifdef CONFIG_NX_LCDDRIVER +# include <nuttx/lcd/lcd.h> +#else +# include <nuttx/fb.h> +#endif + +#include <nuttx/arch.h> +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxglib.h> + +#include "nxlines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ +/* If not specified, assume that the hardware supports one video plane */ + +#ifndef CONFIG_EXAMPLES_NXLINES_VPLANE +# define CONFIG_EXAMPLES_NXLINES_VPLANE 0 +#endif + +/* If not specified, assume that the hardware supports one LCD device */ + +#ifndef CONFIG_EXAMPLES_NXLINES_DEVNO +# define CONFIG_EXAMPLES_NXLINES_DEVNO 0 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct nxlines_data_s g_nxlines = +{ + NULL, /* hnx */ + NULL, /* hbkgd */ + 0, /* xres */ + 0, /* yres */ + false, /* havpos */ + { 0 }, /* sem */ + NXEXIT_SUCCESS /* exit code */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxlines_initialize + ****************************************************************************/ + +static inline int nxlines_initialize(void) +{ + FAR NX_DRIVERTYPE *dev; + +#if defined(CONFIG_EXAMPLES_NXLINES_EXTERNINIT) + /* Use external graphics driver initialization */ + + message("nxlines_initialize: Initializing external graphics device\n"); + dev = up_nxdrvinit(CONFIG_EXAMPLES_NXLINES_DEVNO); + if (!dev) + { + message("nxlines_initialize: up_nxdrvinit failed, devno=%d\n", + CONFIG_EXAMPLES_NXLINES_DEVNO); + g_nxlines.code = NXEXIT_EXTINITIALIZE; + return ERROR; + } + +#elif defined(CONFIG_NX_LCDDRIVER) + int ret; + + /* Initialize the LCD device */ + + message("nxlines_initialize: Initializing LCD\n"); + ret = up_lcdinitialize(); + if (ret < 0) + { + message("nxlines_initialize: up_lcdinitialize failed: %d\n", -ret); + g_nxlines.code = NXEXIT_LCDINITIALIZE; + return ERROR; + } + + /* Get the device instance */ + + dev = up_lcdgetdev(CONFIG_EXAMPLES_NXLINES_DEVNO); + if (!dev) + { + message("nxlines_initialize: up_lcdgetdev failed, devno=%d\n", CONFIG_EXAMPLES_NXLINES_DEVNO); + g_nxlines.code = NXEXIT_LCDGETDEV; + return ERROR; + } + + /* Turn the LCD on at 75% power */ + + (void)dev->setpower(dev, ((3*CONFIG_LCD_MAXPOWER + 3)/4)); +#else + int ret; + + /* Initialize the frame buffer device */ + + message("nxlines_initialize: Initializing framebuffer\n"); + ret = up_fbinitialize(); + if (ret < 0) + { + message("nxlines_initialize: up_fbinitialize failed: %d\n", -ret); + g_nxlines.code = NXEXIT_FBINITIALIZE; + return ERROR; + } + + dev = up_fbgetvplane(CONFIG_EXAMPLES_NXLINES_VPLANE); + if (!dev) + { + message("nxlines_initialize: up_fbgetvplane failed, vplane=%d\n", CONFIG_EXAMPLES_NXLINES_VPLANE); + g_nxlines.code = NXEXIT_FBGETVPLANE; + return ERROR; + } +#endif + + /* Then open NX */ + + message("nxlines_initialize: Open NX\n"); + g_nxlines.hnx = nx_open(dev); + if (!g_nxlines.hnx) + { + message("nxlines_initialize: nx_open failed: %d\n", errno); + g_nxlines.code = NXEXIT_NXOPEN; + return ERROR; + } + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start/nxlines_main + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXLINES_BUILTIN +# define MAIN_NAME nxlines_main +# define MAIN_NAME_STRING "nxlines_main" +#else +# define MAIN_NAME user_start +# define MAIN_NAME_STRING "user_start" +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + nxgl_mxpixel_t color; + int ret; + + /* Initialize NX */ + + ret = nxlines_initialize(); + message(MAIN_NAME_STRING ": NX handle=%p\n", g_nxlines.hnx); + if (!g_nxlines.hnx || ret < 0) + { + message(MAIN_NAME_STRING ": Failed to get NX handle: %d\n", errno); + g_nxlines.code = NXEXIT_NXOPEN; + goto errout; + } + + /* Set the background to the configured background color */ + + message(MAIN_NAME_STRING ": Set background color=%d\n", + CONFIG_EXAMPLES_NXLINES_BGCOLOR); + + color = CONFIG_EXAMPLES_NXLINES_BGCOLOR; + ret = nx_setbgcolor(g_nxlines.hnx, &color); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_setbgcolor failed: %d\n", errno); + g_nxlines.code = NXEXIT_NXSETBGCOLOR; + goto errout_with_nx; + } + + /* Get the background window */ + + ret = nx_requestbkgd(g_nxlines.hnx, &g_bgcb, NULL); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_setbgcolor failed: %d\n", errno); + g_nxlines.code = NXEXIT_NXREQUESTBKGD; + goto errout_with_nx; + } + + /* Wait until we have the screen resolution. We'll have this immediately + * unless we are dealing with the NX server. + */ + + while (!g_nxlines.havepos) + { + (void)sem_wait(&g_nxlines.sem); + } + message(MAIN_NAME_STRING ": Screen resolution (%d,%d)\n", g_nxlines.xres, g_nxlines.yres); + + /* Now, say perform the lines (these test does not return so the remaining + * logic is cosmetic). + */ + + nxlines_test(g_nxlines.hbkgd); + + /* Release background */ + + (void)nx_releasebkgd(g_nxlines.hbkgd); + + /* Close NX */ + +errout_with_nx: + message(MAIN_NAME_STRING ": Close NX\n"); + nx_close(g_nxlines.hnx); +errout: + return g_nxlines.code; +} diff --git a/apps/examples/nxtext/Makefile b/apps/examples/nxtext/Makefile new file mode 100644 index 000000000..75e489943 --- /dev/null +++ b/apps/examples/nxtext/Makefile @@ -0,0 +1,109 @@ +############################################################################ +# apps/examples/nxtext/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttX NX Graphics Example. + +ASRCS = +CSRCS = nxtext_main.c nxtext_bkgd.c nxtext_popup.c nxtext_putc.c + +ifeq ($(CONFIG_NX_MULTIUSER),y) +CSRCS += nxtext_server.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# NXTEXT built-in application info + +APPNAME = nxtext +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_NXTEXT_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/nxtext/nxtext_bkgd.c b/apps/examples/nxtext/nxtext_bkgd.c new file mode 100644 index 000000000..90cc19165 --- /dev/null +++ b/apps/examples/nxtext/nxtext_bkgd.c @@ -0,0 +1,467 @@ +/**************************************************************************** + * examples/nxtext/nxtext_bkgd.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <semaphore.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxfonts.h> + +#include "nxtext_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void nxbg_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool morem, FAR void *arg); +static void nxbg_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg); +#ifdef CONFIG_NX_MOUSE +static void nxbg_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg); +#endif + +#ifdef CONFIG_NX_KBD +static void nxbg_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct nxtext_state_s g_bgstate; +static struct nxtext_bitmap_s g_bgbm[CONFIG_EXAMPLES_NXTEXT_BMCACHE]; +static struct nxtext_glyph_s g_bgglyph[CONFIG_EXAMPLES_NXTEXT_GLCACHE]; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Background window call table */ + +const struct nx_callback_s g_bgcb = +{ + nxbg_redraw, /* redraw */ + nxbg_position /* position */ +#ifdef CONFIG_NX_MOUSE + , nxbg_mousein /* mousein */ +#endif +#ifdef CONFIG_NX_KBD + , nxbg_kbdin /* my kbdin */ +#endif +}; + +/* Background window handle */ + +NXHANDLE g_bgwnd; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxbg_redrawrect + ****************************************************************************/ + +static void nxbg_redrawrect(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect) +{ + int ret; + int i; + + ret = nx_fill(hwnd, rect, g_bgstate.wcolor); + if (ret < 0) + { + message("nxbg_redrawrect: nx_fill failed: %d\n", errno); + } + + /* Fill each character on the display (Only the characters within rect + * will actually be redrawn). + */ + + for (i = 0; i < g_bgstate.nchars; i++) + { + nxtext_fillchar(hwnd, rect, &g_bgstate, g_bghfont, &g_bgstate.bm[i]); + } +} + +/**************************************************************************** + * Name: nxbg_redraw + ****************************************************************************/ + +static void nxbg_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool more, FAR void *arg) +{ + gvdbg("hwnd=%p rect={(%d,%d),(%d,%d)} more=%s\n", + hwnd, rect->pt1.x, rect->pt1.y, rect->pt2.x, rect->pt2.y, + more ? "true" : "false"); + + nxbg_redrawrect(hwnd, rect); +} + +/**************************************************************************** + * Name: nxbg_position + ****************************************************************************/ + +static void nxbg_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg) +{ + FAR struct nxtext_state_s *st = (FAR struct nxtext_state_s *)arg; + + /* Report the position */ + + gvdbg("hwnd=%p size=(%d,%d) pos=(%d,%d) bounds={(%d,%d),(%d,%d)}\n", + hwnd, size->w, size->h, pos->x, pos->y, + bounds->pt1.x, bounds->pt1.y, bounds->pt2.x, bounds->pt2.y); + + /* Have we picked off the window bounds yet? */ + + if (!b_haveresolution) + { + /* Save the background window handle */ + + g_bgwnd = hwnd; + + /* Save the background window size */ + + st->wsize.w = size->w; + st->wsize.h = size->h; + + /* Save the window limits (these should be the same for all places and all windows */ + + g_xres = bounds->pt2.x + 1; + g_yres = bounds->pt2.y + 1; + + b_haveresolution = true; + sem_post(&g_semevent); + gvdbg("Have xres=%d yres=%d\n", g_xres, g_yres); + } +} + +/**************************************************************************** + * Name: nxbg_mousein + ****************************************************************************/ + +#ifdef CONFIG_NX_MOUSE +static void nxbg_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg) +{ + message("nxbg_mousein: hwnd=%p pos=(%d,%d) button=%02x\n", + hwnd, pos->x, pos->y, buttons); +} +#endif + +/**************************************************************************** + * Name: nxbg_kbdin + ****************************************************************************/ + +#ifdef CONFIG_NX_KBD +static void nxbg_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg) +{ + gvdbg("hwnd=%p nch=%d\n", hwnd, nch); + nxbg_write(hwnd, ch, nch); +} +#endif + +/**************************************************************************** + * Name: nxbg_movedisplay + * + * Description: + * This function implements the data movement for the scroll operation. If + * we can read the displays framebuffer memory, then the job is pretty + * easy. However, many displays (such as SPI-based LCDs) are often read- + * only. + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXTEXT_NOGETRUN +static inline void nxbg_movedisplay(NXWINDOW hwnd, int bottom, int lineheight) +{ + FAR struct nxtext_bitmap_s *bm; + struct nxgl_rect_s rect; + nxgl_coord_t row; + int ret; + int i; + + /* Move each row, one at a time. They could all be moved at once (by calling + * nxbg_redrawrect), but the since the region is cleared, then re-written, the + * effect would not be good. Below the region is also cleared and re-written, + * however, in much smaller chunks. + */ + + rect.pt1.x = 0; + rect.pt2.x = g_bgstate.wsize.w - 1; + + for (row = LINE_SEPARATION; row < bottom; row += lineheight) + { + /* Create a bounding box the size of one row of characters */ + + rect.pt1.y = row; + rect.pt2.y = row + lineheight - 1; + + /* Clear the region */ + + ret = nx_fill(hwnd, &rect, g_bgstate.wcolor); + if (ret < 0) + { + message("nxbg_movedisplay: nx_fill failed: %d\n", errno); + } + + /* Fill each character that might lie within in the bounding box */ + + for (i = 0; i < g_bgstate.nchars; i++) + { + bm = &g_bgstate.bm[i]; + if (bm->pos.y <= rect.pt2.y && bm->pos.y + g_bgstate.fheight >= rect.pt1.y) + { + nxtext_fillchar(hwnd, &rect, &g_bgstate, g_bghfont, bm); + } + } + } + + /* Finally, clear the bottom part of the display */ + + rect.pt1.y = bottom; + rect.pt2.y = g_bgstate.wsize.h- 1; + + ret = nx_fill(hwnd, &rect, g_bgstate.wcolor); + if (ret < 0) + { + message("nxbg_movedisplay: nx_fill failed: %d\n", errno); + } +} +#else +static inline void nxbg_movedisplay(NXWINDOW hwnd, int bottom, int lineheight) +{ + struct nxgl_rect_s rect; + struct nxgl_point_s offset; + int ret; + + /* Move the display in the range of 0-height up one lineheight. The + * line at the bottom will be reset to the background color automatically. + * + * The source rectangle to be moved. + */ + + rect.pt1.x = 0; + rect.pt1.y = lineheight + LINE_SEPARATION; + rect.pt2.x = g_bgstate.wsize.w - 1; + rect.pt2.y = g_bgstate.wsize.h - 1; + + /* The offset that determines how far to move the source rectangle */ + + offset.x = 0; + offset.y = -lineheight; + + /* Move the source rectangle */ + + ret = nx_move(hwnd, &rect, &offset); + if (ret < 0) + { + message("nxbg_movedisplay: nx_move failed: %d\n", errno); + } +} +#endif + +/**************************************************************************** + * Name: nxbg_scroll + ****************************************************************************/ + +static inline void nxbg_scroll(NXWINDOW hwnd, int lineheight) +{ + int i; + int j; + + /* Adjust the vertical position of each character */ + + for (i = 0; i < g_bgstate.nchars; ) + { + FAR struct nxtext_bitmap_s *bm = &g_bgstate.bm[i]; + + /* Has any part of this character scrolled off the screen? */ + + if (bm->pos.y < lineheight + LINE_SEPARATION) + { + /* Yes... Delete the character by moving all of the data */ + + for (j = i; j < g_bgstate.nchars-1; j++) + { + memcpy(&g_bgstate.bm[j], &g_bgstate.bm[j+1], sizeof(struct nxtext_bitmap_s)); + } + + /* Decrement the number of cached characters ('i' is not incremented + * in this case because it already points to the next character) + */ + + g_bgstate.nchars--; + } + + /* No.. just decrement its vertical position (moving it "up" the + * display by one line). + */ + + else + { + bm->pos.y -= lineheight; + + /* We are keeping this one so increment to the next character */ + + i++; + } + } + + /* And move the next display position up by one line as well */ + + g_bgstate.fpos.y -= lineheight; + + /* Move the display in the range of 0-height up one lineheight. */ + + nxbg_movedisplay(hwnd, g_bgstate.fpos.y, lineheight); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxbg_getstate + * + * Description: + * Initialize the background window state structure. + * + ****************************************************************************/ + +FAR struct nxtext_state_s *nxbg_getstate(void) +{ + FAR const struct nx_font_s *fontset; + + /* Initialize the color (used for redrawing the window) */ + + memset(&g_bgstate, 0, sizeof(struct nxtext_state_s)); + g_bgstate.wcolor[0] = CONFIG_EXAMPLES_NXTEXT_BGCOLOR; + g_bgstate.fcolor[0] = CONFIG_EXAMPLES_NXTEXT_BGFONTCOLOR; + + /* Get information about the font set being used and save this in the + * state structure + */ + + fontset = nxf_getfontset(g_bghfont); + g_bgstate.fheight = fontset->mxheight; + g_bgstate.fwidth = fontset->mxwidth; + g_bgstate.spwidth = fontset->spwidth; + + /* Set up the text caches */ + + g_bgstate.maxchars = CONFIG_EXAMPLES_NXTEXT_BMCACHE; + g_bgstate.maxglyphs = CONFIG_EXAMPLES_NXTEXT_GLCACHE; + g_bgstate.bm = g_bgbm; + g_bgstate.glyph = g_bgglyph; + + /* Set the first display position */ + + nxtext_home(&g_bgstate); + return &g_bgstate; +} + +/**************************************************************************** + * Name: nxbg_write + * + * Description: + * Put a sequence of bytes in the window. + * + ****************************************************************************/ + +void nxbg_write(NXWINDOW hwnd, FAR const uint8_t *buffer, size_t buflen) +{ + int lineheight = (g_bgstate.fheight + LINE_SEPARATION); + + while (buflen-- > 0) + { + /* Will another character fit on this line? */ + + if (g_bgstate.fpos.x + g_bgstate.fwidth > g_bgstate.wsize.w) + { + /* No.. move to the next line */ + + nxtext_newline(&g_bgstate); + + /* If we were about to output a newline character, then don't */ + + if (*buffer == '\n') + { + buffer++; + continue; + } + } + + /* Check if we need to scroll up (handling a corner case where + * there may be more than one newline). + */ + + while (g_bgstate.fpos.y >= g_bgstate.wsize.h - lineheight) + { + nxbg_scroll(hwnd, lineheight); + } + + /* Finally, we can output the character */ + + nxtext_putc(hwnd, &g_bgstate, g_bghfont, (uint8_t)*buffer++); + } +} diff --git a/apps/examples/nxtext/nxtext_internal.h b/apps/examples/nxtext/nxtext_internal.h new file mode 100644 index 000000000..caf8cd9fc --- /dev/null +++ b/apps/examples/nxtext/nxtext_internal.h @@ -0,0 +1,330 @@ +/**************************************************************************** + * examples/nxtext/nxtext_internal.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_NXTEXT_NXTEXT_INTERNAL_H +#define __EXAMPLES_NXTEXT_NXTEXT_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <semaphore.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxtk.h> +#include <nuttx/nx/nxfonts.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_NX +# error "NX is not enabled (CONFIG_NX)" +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_VPLANE +# define CONFIG_EXAMPLES_NXTEXT_VPLANE 0 +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_BPP +# define CONFIG_EXAMPLES_NXTEXT_BPP 32 +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_BGCOLOR +# if CONFIG_EXAMPLES_NXTEXT_BPP == 24 || CONFIG_EXAMPLES_NXTEXT_BPP == 32 +# define CONFIG_EXAMPLES_NXTEXT_BGCOLOR 0x007b68ee +# elif CONFIG_EXAMPLES_NXTEXT_BPP == 16 +# define CONFIG_EXAMPLES_NXTEXT_BGCOLOR 0x7b5d +# else +# define CONFIG_EXAMPLES_NXTEXT_BGCOLOR ' ' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_PUFONTID +# define CONFIG_EXAMPLES_NXTEXT_PUFONTID NXFONT_DEFAULT +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_PUCOLOR +# if CONFIG_EXAMPLES_NXTEXT_BPP == 24 || CONFIG_EXAMPLES_NXTEXT_BPP == 32 +# define CONFIG_EXAMPLES_NXTEXT_PUCOLOR 0x00dcdcdc +# elif CONFIG_EXAMPLES_NXTEXT_BPP == 16 +# define CONFIG_EXAMPLES_NXTEXT_PUCOLOR 0xdefb +# else +# define CONFIG_EXAMPLES_NXTEXT_PUCOLOR '2' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_BGFONTID +# define CONFIG_EXAMPLES_NXTEXT_BGFONTID NXFONT_DEFAULT +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_BGFONTCOLOR +# if CONFIG_EXAMPLES_NXTEXT_BPP == 24 || CONFIG_EXAMPLES_NXTEXT_BPP == 32 +# define CONFIG_EXAMPLES_NXTEXT_BGFONTCOLOR 0x00000000 +# elif CONFIG_EXAMPLES_NXTEXT_BPP == 16 +# define CONFIG_EXAMPLES_NXTEXT_BGFONTCOLOR 0x0000 +# else +# define CONFIG_EXAMPLES_NXTEXT_BGFONTCOLOR 'F' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_PUFONTCOLOR +# if CONFIG_EXAMPLES_NXTEXT_BPP == 24 || CONFIG_EXAMPLES_NXTEXT_BPP == 32 +# define CONFIG_EXAMPLES_NXTEXT_PUFONTCOLOR 0x00000000 +# elif CONFIG_EXAMPLES_NXTEXT_BPP == 16 +# define CONFIG_EXAMPLES_NXTEXT_PUFONTCOLOR 0x0000 +# else +# define CONFIG_EXAMPLES_NXTEXT_PUFONTCOLOR 'F' +# endif +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_BMCACHE +# define CONFIG_EXAMPLES_NXTEXT_BMCACHE 128 +#endif + +#ifndef CONFIG_EXAMPLES_NXTEXT_GLCACHE +# define CONFIG_EXAMPLES_NXTEXT_BMCACHE 16 +#endif + +#ifdef CONFIG_NX_MULTIUSER +# ifdef CONFIG_DISABLE_MQUEUE +# error "The multi-threaded example requires MQ support (CONFIG_DISABLE_MQUEUE=n)" +# endif +# ifdef CONFIG_DISABLE_SIGNALS +# error "This example requires signal support (CONFIG_DISABLE_SIGNALS=n)" +# endif +# ifdef CONFIG_DISABLE_PTHREAD +# error "This example requires pthread support (CONFIG_DISABLE_PTHREAD=n)" +# endif +# ifndef CONFIG_NX_BLOCKING +# error "This example depends on CONFIG_NX_BLOCKING" +# endif +# ifndef CONFIG_EXAMPLES_NXTEXT_STACKSIZE +# define CONFIG_EXAMPLES_NXTEXT_STACKSIZE 2048 +# endif +# ifndef CONFIG_EXAMPLES_NXTEXT_LISTENERPRIO +# define CONFIG_EXAMPLES_NXTEXT_LISTENERPRIO 100 +# endif +# ifndef CONFIG_EXAMPLES_NXTEXT_CLIENTPRIO +# define CONFIG_EXAMPLES_NXTEXT_CLIENTPRIO 100 +# endif +# ifndef CONFIG_EXAMPLES_NXTEXT_SERVERPRIO +# define CONFIG_EXAMPLES_NXTEXT_SERVERPRIO 120 +# endif +# ifndef CONFIG_EXAMPLES_NXTEXT_NOTIFYSIGNO +# define CONFIG_EXAMPLES_NXTEXT_NOTIFYSIGNO 4 +# endif +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +/* Bitmap flags */ + +#define BMFLAGS_NOGLYPH (1 << 0) /* No glyph available, use space */ + +#define BM_ISSPACE(bm) (((bm)->flags & BMFLAGS_NOGLYPH) != 0) + +/* Sizes and maximums */ + +#define MAX_USECNT 255 /* Limit to range of a uint8_t */ +#define LINE_SEPARATION 2 /* Space (in rows) between lines */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum exitcode_e +{ + NXEXIT_SUCCESS = 0, + NXEXIT_SCHEDSETPARAM, + NXEXIT_TASKCREATE, + NXEXIT_PTHREADCREATE, + NXEXIT_EXTINITIALIZE, + NXEXIT_FBINITIALIZE, + NXEXIT_FBGETVPLANE, + NXEXIT_LCDINITIALIZE, + NXEXIT_LCDGETDEV, + NXEXIT_NXOPEN, + NXEXIT_FONTOPEN, + NXEXIT_NXREQUESTBKGD, + NXEXIT_NXCONNECT, + NXEXIT_NXSETBGCOLOR, + NXEXIT_NXOPENWINDOW, + NXEXIT_NXSETSIZE, + NXEXIT_NXSETPOSITION, + NXEXIT_NXCLOSEWINDOW, + NXEXIT_LOSTSERVERCONN +}; + +/* Describes one cached glyph bitmap */ + +struct nxtext_glyph_s +{ + uint8_t code; /* Character code */ + uint8_t height; /* Height of this glyph (in rows) */ + uint8_t width; /* Width of this glyph (in pixels) */ + uint8_t stride; /* Width of the glyph row (in bytes) */ + uint8_t usecnt; /* Use count */ + FAR uint8_t *bitmap; /* Allocated bitmap memory */ +}; + +/* Describes on character on the display */ + +struct nxtext_bitmap_s +{ + uint8_t code; /* Character code */ + uint8_t flags; /* See BMFLAGS_* */ + struct nxgl_point_s pos; /* Character position */ +}; + +/* Describes the state of one text display */ + +struct nxtext_state_s +{ + /* The following describe the window */ + + nxgl_mxpixel_t wcolor[CONFIG_NX_NPLANES]; /* Window color */ + struct nxgl_size_s wsize; /* Window size */ + struct nxgl_point_s wpos; /* Window position */ + + /* These characterize the font in use */ + + nxgl_mxpixel_t fcolor[CONFIG_NX_NPLANES]; /* Font color */ + uint8_t fheight; /* Max height of a font in pixels */ + uint8_t fwidth; /* Max width of a font in pixels */ + uint8_t spwidth; /* The width of a space */ + struct nxgl_point_s fpos; /* Next display position */ + + /* These describe all text already added to the display */ + + uint8_t maxglyphs; /* Size of the glyph[] array */ + uint16_t maxchars; /* Size of the bm[] array */ + uint16_t nchars; /* Number of chars in the bm[] array */ + + FAR struct nxtext_bitmap_s *bm; /* List of characters on the display */ + FAR struct nxtext_glyph_s *glyph; /* Cache of rendered fonts in use */ +}; + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/* The connecton handler */ + +extern NXHANDLE g_hnx; + +/* Background window handle */ + +extern NXHANDLE g_bgwnd; + +/* The font handlse */ + +extern NXHANDLE g_bghfont; +extern NXHANDLE g_puhfont; + +/* NX callback vtables */ + +extern const struct nx_callback_s g_bgcb; + +/* The screen resolution */ + +extern nxgl_coord_t g_xres; +extern nxgl_coord_t g_yres; + +extern bool b_haveresolution; +#ifdef CONFIG_NX_MULTIUSER +extern bool g_connected; +#endif +extern sem_t g_semevent; + +extern int g_exitcode; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXTEXT_EXTERNINIT +extern FAR NX_DRIVERTYPE *up_nxdrvinit(unsigned int devno); +#endif +#if defined(CONFIG_NX) && defined(CONFIG_NX_MULTIUSER) +extern int nxtext_server(int argc, char *argv[]); +extern FAR void *nxtext_listener(FAR void *arg); +#endif + +/* Background window interfaces */ + +extern FAR struct nxtext_state_s *nxbg_getstate(void); +extern void nxbg_write(NXWINDOW hwnd, FAR const uint8_t *buffer, size_t buflen); + +/* Pop-up window interfaces */ + +extern NXWINDOW nxpu_open(void); +extern int nxpu_close(NXWINDOW hwnd); + +/* Generic text helpers */ + +extern void nxtext_home(FAR struct nxtext_state_s *st); +extern void nxtext_newline(FAR struct nxtext_state_s *st); +extern void nxtext_putc(NXWINDOW hwnd, FAR struct nxtext_state_s *st, + NXHANDLE hfont, uint8_t ch); +extern void nxtext_fillchar(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + FAR struct nxtext_state_s *st, NXHANDLE hfont, + FAR const struct nxtext_bitmap_s *bm); + +#endif /* __EXAMPLES_NXTEXT_NXTEXT_INTERNAL_H */ diff --git a/apps/examples/nxtext/nxtext_main.c b/apps/examples/nxtext/nxtext_main.c new file mode 100644 index 000000000..b7e2a3356 --- /dev/null +++ b/apps/examples/nxtext/nxtext_main.c @@ -0,0 +1,512 @@ +/**************************************************************************** + * examples/nxtext/nxtext_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <string.h> +#include <sched.h> +#include <pthread.h> +#include <errno.h> +#include <debug.h> + +#ifdef CONFIG_NX_LCDDRIVER +# include <nuttx/lcd/lcd.h> +#else +# include <nuttx/fb.h> +#endif + +#include <nuttx/arch.h> +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxglib.h> +#include <nuttx/nx/nxfonts.h> + +#include "nxtext_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ +/* If not specified, assume that the hardware supports one video plane */ + +#ifndef CONFIG_EXAMPLES_NXTEXT_VPLANE +# define CONFIG_EXAMPLES_NXTEXT_VPLANE 0 +#endif + +/* If not specified, assume that the hardware supports one LCD device */ + +#ifndef CONFIG_EXAMPLES_NXTEXT_DEVNO +# define CONFIG_EXAMPLES_NXTEXT_DEVNO 0 +#endif + +#define BGMSG_LINES 24 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_NX_KBD +static const uint8_t g_pumsg[] = "Pop-Up!"; +static const char *g_bgmsg[BGMSG_LINES] = +{ + "\nJULIET\n", /* Line 1 */ + "Wilt thou be gone?\n", /* Line 2 */ + " It is not yet near day:\n", /* Line 3 */ + "It was the nightingale,\n", /* Line 4 */ + " and not the lark,\n", /* Line 5 */ + "That pierced the fearful hollow\n", /* Line 6 */ + " of thine ear;\n", /* Line 7 */ + "Nightly she sings\n", /* Line 8 */ + " on yon pomegranate-tree:\n", /* Line 9 */ + "Believe me, love,\n", /* Line 10 */ + " it was the nightingale.\n", /* Line 11 */ + "\nROMEO\n", /* Line 12 */ + "It was the lark,\n", /* Line 13 */ + " the herald of the morn,\n", /* Line 14 */ + "No nightingale:\n", /* Line 15 */ + " look, love, what envious streaks\n", /* Line 16 */ + "Do lace the severing clouds\n", /* Line 17 */ + " in yonder east:\n", /* Line 18 */ + "Night's candles are burnt out,\n", /* Line 19 */ + " and jocund day\n", /* Line 20 */ + "Stands tiptoe\n", /* Line 21 */ + " on the misty mountain tops.\n", /* Line 22 */ + "I must be gone and live,\n", /* Line 23 */ + " or stay and die.\n" /* Line 24 */ +}; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* The connecton handler */ + +NXHANDLE g_hnx = NULL; + +/* The font handles */ + +NXHANDLE g_bghfont = NULL; +NXHANDLE g_puhfont = NULL; + +/* The screen resolution */ + +nxgl_coord_t g_xres; +nxgl_coord_t g_yres; + +bool b_haveresolution = false; +#ifdef CONFIG_NX_MULTIUSER +bool g_connected = false; +#endif +sem_t g_semevent = {0}; + +int g_exitcode = NXEXIT_SUCCESS; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxtext_suinitialize + ****************************************************************************/ + +#ifndef CONFIG_NX_MULTIUSER +static inline int nxtext_suinitialize(void) +{ + FAR NX_DRIVERTYPE *dev; + +#if defined(CONFIG_EXAMPLES_NXTEXT_EXTERNINIT) + /* Use external graphics driver initialization */ + + message("nxtext_initialize: Initializing external graphics device\n"); + dev = up_nxdrvinit(CONFIG_EXAMPLES_NXTEXT_DEVNO); + if (!dev) + { + message("nxtext_initialize: up_nxdrvinit failed, devno=%d\n", CONFIG_EXAMPLES_NXTEXT_DEVNO); + g_exitcode = NXEXIT_EXTINITIALIZE; + return ERROR; + } + +#elif defined(CONFIG_NX_LCDDRIVER) + int ret; + + /* Initialize the LCD device */ + + message("nxtext_initialize: Initializing LCD\n"); + ret = up_lcdinitialize(); + if (ret < 0) + { + message("nxtext_initialize: up_lcdinitialize failed: %d\n", -ret); + g_exitcode = NXEXIT_LCDINITIALIZE; + return ERROR; + } + + /* Get the device instance */ + + dev = up_lcdgetdev(CONFIG_EXAMPLES_NXTEXT_DEVNO); + if (!dev) + { + message("nxtext_initialize: up_lcdgetdev failed, devno=%d\n", CONFIG_EXAMPLES_NXTEXT_DEVNO); + g_exitcode = NXEXIT_LCDGETDEV; + return ERROR; + } + + /* Turn the LCD on at 75% power */ + + (void)dev->setpower(dev, ((3*CONFIG_LCD_MAXPOWER + 3)/4)); +#else + int ret; + + /* Initialize the frame buffer device */ + + message("nxtext_initialize: Initializing framebuffer\n"); + ret = up_fbinitialize(); + if (ret < 0) + { + message("nxtext_initialize: up_fbinitialize failed: %d\n", -ret); + g_exitcode = NXEXIT_FBINITIALIZE; + return ERROR; + } + + dev = up_fbgetvplane(CONFIG_EXAMPLES_NXTEXT_VPLANE); + if (!dev) + { + message("nxtext_initialize: up_fbgetvplane failed, vplane=%d\n", CONFIG_EXAMPLES_NXTEXT_VPLANE); + g_exitcode = NXEXIT_FBGETVPLANE; + return ERROR; + } +#endif + + /* Then open NX */ + + message("nxtext_initialize: Open NX\n"); + g_hnx = nx_open(dev); + if (!g_hnx) + { + message("nxtext_initialize: nx_open failed: %d\n", errno); + g_exitcode = NXEXIT_NXOPEN; + return ERROR; + } + return OK; +} +#endif + +/**************************************************************************** + * Name: nxtext_initialize + ****************************************************************************/ + +#ifdef CONFIG_NX_MULTIUSER +static inline int nxtext_muinitialize(void) +{ + struct sched_param param; + pthread_t thread; + pid_t servrid; + int ret; + + /* Set the client task priority */ + + param.sched_priority = CONFIG_EXAMPLES_NXTEXT_CLIENTPRIO; + ret = sched_setparam(0, ¶m); + if (ret < 0) + { + message("nxtext_initialize: sched_setparam failed: %d\n" , ret); + g_exitcode = NXEXIT_SCHEDSETPARAM; + return ERROR; + } + + /* Start the server task */ + + message("nxtext_initialize: Starting nxtext_server task\n"); + servrid = task_create("NX Server", CONFIG_EXAMPLES_NXTEXT_SERVERPRIO, + CONFIG_EXAMPLES_NXTEXT_STACKSIZE, nxtext_server, NULL); + if (servrid < 0) + { + message("nxtext_initialize: Failed to create nxtext_server task: %d\n", errno); + g_exitcode = NXEXIT_TASKCREATE; + return ERROR; + } + + /* Wait a bit to let the server get started */ + + sleep(1); + + /* Connect to the server */ + + g_hnx = nx_connect(); + if (g_hnx) + { + pthread_attr_t attr; + + /* Start a separate thread to listen for server events. This is probably + * the least efficient way to do this, but it makes this example flow more + * smoothly. + */ + + (void)pthread_attr_init(&attr); + param.sched_priority = CONFIG_EXAMPLES_NXTEXT_LISTENERPRIO; + (void)pthread_attr_setschedparam(&attr, ¶m); + (void)pthread_attr_setstacksize(&attr, CONFIG_EXAMPLES_NXTEXT_STACKSIZE); + + ret = pthread_create(&thread, &attr, nxtext_listener, NULL); + if (ret != 0) + { + printf("nxtext_initialize: pthread_create failed: %d\n", ret); + g_exitcode = NXEXIT_PTHREADCREATE; + return ERROR; + } + + /* Don't return until we are connected to the server */ + + while (!g_connected) + { + /* Wait for the listener thread to wake us up when we really + * are connected. + */ + + (void)sem_wait(&g_semevent); + } + } + else + { + message("nxtext_initialize: nx_connect failed: %d\n", errno); + g_exitcode = NXEXIT_NXCONNECT; + return ERROR; + } + return OK; +} +#endif + +/**************************************************************************** + * Name: nxtext_initialize + ****************************************************************************/ + +static int nxtext_initialize(void) +{ +#ifdef CONFIG_NX_MULTIUSER + return nxtext_muinitialize(); +#else + return nxtext_suinitialize(); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start/nxtext_main + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_NXTEXT_BUILTIN +# define MAIN_NAME nxtext_main +# define MAIN_NAME_STRING "nxtext_main" +#else +# define MAIN_NAME user_start +# define MAIN_NAME_STRING "user_start" +#endif + +int MAIN_NAME(int argc, char **argv) +{ + FAR struct nxtext_state_s *bgstate; + NXWINDOW hwnd = NULL; + nxgl_mxpixel_t color; + int popcnt; + int bkgndx; + int ret; + + /* Initialize NX */ + + ret = nxtext_initialize(); + message(MAIN_NAME_STRING ": NX handle=%p\n", g_hnx); + if (!g_hnx || ret < 0) + { + message(MAIN_NAME_STRING ": Failed to get NX handle: %d\n", errno); + g_exitcode = NXEXIT_NXOPEN; + goto errout; + } + + /* Get the configured font handles */ + + g_bghfont = nxf_getfonthandle(CONFIG_EXAMPLES_NXTEXT_BGFONTID); + if (!g_bghfont) + { + message(MAIN_NAME_STRING ": Failed to get background font handle: %d\n", errno); + g_exitcode = NXEXIT_FONTOPEN; + goto errout; + } + + g_puhfont = nxf_getfonthandle(CONFIG_EXAMPLES_NXTEXT_PUFONTID); + if (!g_puhfont) + { + message(MAIN_NAME_STRING ": Failed to get pop-up font handle: %d\n", errno); + g_exitcode = NXEXIT_FONTOPEN; + goto errout; + } + + /* Set the background to the configured background color */ + + message(MAIN_NAME_STRING ": Set background color=%d\n", CONFIG_EXAMPLES_NXTEXT_BGCOLOR); + color = CONFIG_EXAMPLES_NXTEXT_BGCOLOR; + ret = nx_setbgcolor(g_hnx, &color); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_setbgcolor failed: %d\n", errno); + g_exitcode = NXEXIT_NXSETBGCOLOR; + goto errout_with_nx; + } + + /* Get the background window */ + + bgstate = nxbg_getstate(); + ret = nx_requestbkgd(g_hnx, &g_bgcb, bgstate); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_setbgcolor failed: %d\n", errno); + g_exitcode = NXEXIT_NXREQUESTBKGD; + goto errout_with_nx; + } + + /* Wait until we have the screen resolution. We'll have this immediately + * unless we are dealing with the NX server. + */ + + while (!b_haveresolution) + { + (void)sem_wait(&g_semevent); + } + message(MAIN_NAME_STRING ": Screen resolution (%d,%d)\n", g_xres, g_yres); + + /* Now loop, adding text to the background and periodically presenting + * a pop-up window. + */ + + popcnt = 0; + bkgndx = 0; + for (;;) + { + /* Sleep for one second */ + + sleep(1); + popcnt++; + + /* Each three seconds, create a pop-up window. Destroy the pop-up + * window after two more seconds. + */ + + if (popcnt == 3) + { + /* Create a pop-up window */ + + hwnd = nxpu_open(); + + /* Give keyboard input to the top window (which should be the pop-up) */ + +#ifdef CONFIG_NX_KBD + message(MAIN_NAME_STRING ": Send keyboard input: %s\n", g_pumsg); + ret = nx_kbdin(g_hnx, strlen((FAR const char *)g_pumsg), g_pumsg); + if (ret < 0) + { + message(MAIN_NAME_STRING ": nx_kbdin failed: %d\n", errno); + goto errout_with_hwnd; + } +#endif + } + else if (popcnt == 5) + { + /* Destroy the pop-up window and restart the sequence */ + + message(MAIN_NAME_STRING ": Close pop-up\n"); + (void)nxpu_close(hwnd); + popcnt = 0; + } + + /* Give another line of text to the background window. Force this + * text to go the background by calling the background window interfaces + * directly. + */ + + nxbg_write(g_bgwnd, (FAR const uint8_t *)g_bgmsg[bkgndx], strlen(g_bgmsg[bkgndx])); + if (++bkgndx >= BGMSG_LINES) + { + bkgndx = 0; + } + } + + /* Close the pop-up window */ + +errout_with_hwnd: + if (popcnt >= 3) + { + message(MAIN_NAME_STRING ": Close pop-up\n"); + (void)nxpu_close(hwnd); + } + +//errout_with_bkgd: + (void)nx_releasebkgd(g_bgwnd); + +errout_with_nx: +#ifdef CONFIG_NX_MULTIUSER + /* Disconnect from the server */ + + message(MAIN_NAME_STRING ": Disconnect from the server\n"); + nx_disconnect(g_hnx); +#else + /* Close the server */ + + message(MAIN_NAME_STRING ": Close NX\n"); + nx_close(g_hnx); +#endif +errout: + return g_exitcode; +} diff --git a/apps/examples/nxtext/nxtext_popup.c b/apps/examples/nxtext/nxtext_popup.c new file mode 100644 index 000000000..f00f6a040 --- /dev/null +++ b/apps/examples/nxtext/nxtext_popup.c @@ -0,0 +1,408 @@ +/**************************************************************************** + * examples/nxtext/nxtext_popup.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <semaphore.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxfonts.h> + +#include "nxtext_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define NBM_CACHE 8 +#define NGLYPH_CACHE 8 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void nxpu_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool morem, FAR void *arg); +static void nxpu_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg); +#ifdef CONFIG_NX_MOUSE +static void nxpu_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg); +#endif + +#ifdef CONFIG_NX_KBD +static void nxpu_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Pop-up NX callbacks */ + +static const struct nx_callback_s g_pucb = +{ + nxpu_redraw, /* redraw */ + nxpu_position /* position */ +#ifdef CONFIG_NX_MOUSE + , nxpu_mousein /* mousein */ +#endif +#ifdef CONFIG_NX_KBD + , nxpu_kbdin /* my kbdin */ +#endif +}; + +/* Pop-up state information */ + +static struct nxtext_state_s g_pustate; +#ifdef CONFIG_NX_KBD +static struct nxtext_bitmap_s g_pubm[NBM_CACHE]; +static struct nxtext_glyph_s g_puglyph[NGLYPH_CACHE]; +#endif + +/* Some random numbers */ + +static const uint8_t g_rand8[9] = +{ + 0x18, 0x8d, 0x60, 0x42, 0xb7, 0xc2, 0x2d, 0xea, 0x6b +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxpu_randpos + ****************************************************************************/ + +static fb_coord_t nxpu_randpos(fb_coord_t value) +{ + static uint8_t ndx = 0; + uint8_t rand8 = g_rand8[ndx]; + + if (++ndx >= 9) + { + ndx = 0; + } + + return (fb_coord_t)(((uint32_t)value * (uint32_t)rand8) >> 8); +} + +/**************************************************************************** + * Name: nxpu_setsize + ****************************************************************************/ + +static inline int nxpu_setsize(NXWINDOW hwnd, FAR struct nxgl_size_s *size) +{ + int ret = nx_setsize(hwnd, size); + if (ret < 0) + { + message("nxpu_setsize: nx_setsize failed: %d\n", errno); + g_exitcode = NXEXIT_NXSETSIZE; + } + return ret; +} + +/**************************************************************************** + * Name: nxpu_setposition + ****************************************************************************/ + +static inline int nxpu_setposition(NXWINDOW hwnd, FAR struct nxgl_point_s *pos) +{ + int ret = nx_setposition(hwnd, pos); + if (ret < 0) + { + message("nxpu_setposition: nx_setposition failed: %d\n", errno); + g_exitcode = NXEXIT_NXSETPOSITION; + } + return ret; +} + +/**************************************************************************** + * Name: nxpu_fillwindow + ****************************************************************************/ + +static inline void nxpu_fillwindow(NXWINDOW hwnd, + FAR const struct nxgl_rect_s *rect, + FAR struct nxtext_state_s *st) +{ + int ret; + int i; + + ret = nx_fill(hwnd, rect, st->wcolor); + if (ret < 0) + { + message("nxpu_fillwindow: nx_fill failed: %d\n", errno); + } + + /* Fill each character on the display (Only the characters within rect + * will actually be redrawn). + */ + +#ifdef CONFIG_NX_KBD + nxtext_home(st); + for (i = 0; i < st->nchars; i++) + { + nxtext_fillchar(hwnd, rect, st, g_puhfont, &st->bm[i]); + } +#endif +} + +/**************************************************************************** + * Name: nxpu_redraw + ****************************************************************************/ + +static void nxpu_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + bool more, FAR void *arg) +{ + FAR struct nxtext_state_s *st = (FAR struct nxtext_state_s *)arg; + gvdbg("hwnd=%p rect={(%d,%d),(%d,%d)} more=%s\n", + hwnd, rect->pt1.x, rect->pt1.y, rect->pt2.x, rect->pt2.y, + more ? "true" : "false"); + + nxpu_fillwindow(hwnd, rect, st); +} + +/**************************************************************************** + * Name: nxpu_position + ****************************************************************************/ + +static void nxpu_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, + FAR const struct nxgl_point_s *pos, + FAR const struct nxgl_rect_s *bounds, + FAR void *arg) +{ + FAR struct nxtext_state_s *st = (FAR struct nxtext_state_s *)arg; + + /* Report the position */ + + gvdbg("hwnd=%p size=(%d,%d) pos=(%d,%d) bounds={(%d,%d),(%d,%d)}\n", + hwnd, size->w, size->h, pos->x, pos->y, + bounds->pt1.x, bounds->pt1.y, bounds->pt2.x, bounds->pt2.y); + + /* Save the window position and size */ + + st->wpos.x = pos->x; + st->wpos.y = pos->y; + + st->wsize.w = size->w; + st->wsize.h = size->h; +} + +/**************************************************************************** + * Name: nxpu_mousein + ****************************************************************************/ + +#ifdef CONFIG_NX_MOUSE +static void nxpu_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos, + uint8_t buttons, FAR void *arg) +{ + message("nxpu_mousein: hwnd=%p pos=(%d,%d) button=%02x\n", + hwnd, pos->x, pos->y, buttons); +} +#endif + +/**************************************************************************** + * Name: nxpu_puts + ****************************************************************************/ + +static inline void nxpu_puts(NXWINDOW hwnd, FAR struct nxtext_state_s *st, + uint8_t nch, FAR const uint8_t *ch) +{ + nxtext_home(st); + while (nch--) + { + nxtext_putc(hwnd, st, g_puhfont, *ch++); + } +} + +/**************************************************************************** + * Name: nxpu_kbdin + ****************************************************************************/ + +#ifdef CONFIG_NX_KBD +static void nxpu_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, + FAR void *arg) +{ + FAR struct nxtext_state_s *st = (FAR struct nxtext_state_s *)arg; + gvdbg("hwnd=%p nch=%d\n", hwnd, nch); + nxpu_puts(hwnd, st, nch, ch); +} +#endif + +/**************************************************************************** + * Name: nxpu_initstate + ****************************************************************************/ + +static inline void nxpu_initstate(void) +{ +#ifdef CONFIG_NX_KBD + FAR const struct nx_font_s *fontset; +#endif + + /* Initialize the color (used for redrawing the window) */ + + memset(&g_pustate, 0, sizeof(struct nxtext_state_s)); + g_pustate.wcolor[0] = CONFIG_EXAMPLES_NXTEXT_PUCOLOR; + g_pustate.fcolor[0] = CONFIG_EXAMPLES_NXTEXT_PUFONTCOLOR; + + /* Get information about the font set being used and save this in the + * state structure + */ + +#ifdef CONFIG_NX_KBD + fontset = nxf_getfontset(g_puhfont); + g_pustate.fheight = fontset->mxheight; + g_pustate.fwidth = fontset->mxwidth; + g_pustate.spwidth = fontset->spwidth; + + /* Set up the text caches */ + + g_pustate.maxchars = NBM_CACHE; + g_pustate.maxglyphs = NGLYPH_CACHE; + g_pustate.bm = g_pubm; + g_pustate.glyph = g_puglyph; + + /* Set the first display position */ + + nxtext_home(&g_pustate); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxpu_open + ****************************************************************************/ + +NXWINDOW nxpu_open(void) +{ + NXWINDOW hwnd; + struct nxgl_size_s size; + struct nxgl_point_s pt; + int ret; + + /* Create a pop-up window */ + + message("nxpu_open: Create pop-up\n"); + nxpu_initstate(); + + hwnd = nx_openwindow(g_hnx, &g_pucb, (FAR void *)&g_pustate); + gvdbg("hwnd=%p\n", hwnd); + + if (!hwnd) + { + message("nxpu_open: nx_openwindow failed: %d\n", errno); + g_exitcode = NXEXIT_NXOPENWINDOW; + goto errout_with_state; + } + + /* Select the size of the pop-up window */ + + size.w = g_xres / 4; + size.h = g_yres / 4; + + /* Select a random position for pop-up window */ + + pt.x = nxpu_randpos(g_xres - size.w); + pt.y = nxpu_randpos(g_yres - size.h); + + /* Set the position for the pop-up window */ + + message("nxpu_open: Set pop-up postion to (%d,%d)\n", pt.x, pt.y); + ret = nxpu_setposition(hwnd, &pt); + if (ret < 0) + { + goto errout_with_hwnd; + } + + /* Set the size of the pop-up window */ + + gvdbg("Set pop-up size to (%d,%d)\n", size.w, size.h); + ret = nxpu_setsize(hwnd, &size); + if (ret < 0) + { + goto errout_with_hwnd; + } + + return hwnd; + +errout_with_hwnd: + (void)nx_closewindow(hwnd); + +errout_with_state: + return NULL; +} + +/**************************************************************************** + * Name: nxpu_close + ****************************************************************************/ + +int nxpu_close(NXWINDOW hwnd) +{ + int ret; + + ret = nx_closewindow(hwnd); + if (ret < 0) + { + message("nxpu_close: nx_closewindow failed: %d\n", errno); + g_exitcode = NXEXIT_NXCLOSEWINDOW; + return ret; + } + return OK; +} diff --git a/apps/examples/nxtext/nxtext_putc.c b/apps/examples/nxtext/nxtext_putc.c new file mode 100644 index 000000000..dfecfe33f --- /dev/null +++ b/apps/examples/nxtext/nxtext_putc.c @@ -0,0 +1,598 @@ +/**************************************************************************** + * examples/nxtext/nxtext_putc.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/nx/nx.h> +#include <nuttx/nx/nxtk.h> +#include <nuttx/nx/nxfonts.h> + +#include "nxtext_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Select renderer -- Some additional logic would be required to support + * pixel depths that are not directly addressable (1,2,4, and 24). + */ + +#if CONFIG_EXAMPLES_NXTEXT_BPP == 1 +# define RENDERER nxf_convert_1bpp +#elif CONFIG_EXAMPLES_NXTEXT_BPP == 2 +# define RENDERER nxf_convert_2bpp +#elif CONFIG_EXAMPLES_NXTEXT_BPP == 4 +# define RENDERER nxf_convert_4bpp +#elif CONFIG_EXAMPLES_NXTEXT_BPP == 8 +# define RENDERER nxf_convert_8bpp +#elif CONFIG_EXAMPLES_NXTEXT_BPP == 16 +# define RENDERER nxf_convert_16bpp +#elif CONFIG_EXAMPLES_NXTEXT_BPP == 24 +# define RENDERER nxf_convert_24bpp +#elif CONFIG_EXAMPLES_NXTEXT_BPP == 32 +# define RENDERER nxf_convert_32bpp +#else +# error "Unsupported CONFIG_EXAMPLES_NXTEXT_BPP" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxtext_freeglyph + ****************************************************************************/ + +static void nxtext_freeglyph(FAR struct nxtext_glyph_s *glyph) +{ + if (glyph->bitmap) + { + free(glyph->bitmap); + } + memset(glyph, 0, sizeof(struct nxtext_glyph_s)); +} + +/**************************************************************************** + * Name: nxtext_allocglyph + ****************************************************************************/ + +static inline FAR struct nxtext_glyph_s * +nxtext_allocglyph(FAR struct nxtext_state_s *st) +{ + FAR struct nxtext_glyph_s *glyph = NULL; + FAR struct nxtext_glyph_s *luglyph = NULL; + uint8_t luusecnt; + int i; + + /* Search through the glyph cache looking for an unused glyph. Also, keep + * track of the least used glyph as well. We need that if we have to replace + * a glyph in the cache. + */ + + for (i = 0; i < st->maxglyphs; i++) + { + /* Is this glyph in use? */ + + glyph = &st->glyph[i]; + if (!glyph->usecnt) + { + /* No.. return this glyph with a use count of one */ + + glyph->usecnt = 1; + return glyph; + } + + /* Yes.. check for the least recently used */ + + if (!luglyph || glyph->usecnt < luglyph->usecnt) + { + luglyph = glyph; + } + } + + /* If we get here, the glyph cache is full. We replace the least used + * glyph with the one we need now. (luglyph can't be NULL). + */ + + luusecnt = luglyph->usecnt; + nxtext_freeglyph(luglyph); + + /* But lets decrement all of the usecnts so that the new one one be so + * far behind in the counts as the older ones. + */ + + if (luusecnt > 1) + { + uint8_t decr = luusecnt - 1; + + for (i = 0; i < st->maxglyphs; i++) + { + /* Is this glyph in use? */ + + glyph = &st->glyph[i]; + if (glyph->usecnt > decr) + { + glyph->usecnt -= decr; + } + } + } + + /* Then return the least used glyph */ + + luglyph->usecnt = 1; + return luglyph; +} + +/**************************************************************************** + * Name: nxtext_findglyph + ****************************************************************************/ + +static FAR struct nxtext_glyph_s * +nxtext_findglyph(FAR struct nxtext_state_s *st, uint8_t ch) +{ + int i; + + /* First, try to find the glyph in the cache of pre-rendered glyphs */ + + for (i = 0; i < st->maxglyphs; i++) + { + FAR struct nxtext_glyph_s *glyph = &st->glyph[i]; + if (glyph->usecnt > 0 && glyph->code == ch) + { + /* Increment the use count (unless it is already at the max) */ + + if (glyph->usecnt < MAX_USECNT) + { + glyph->usecnt++; + } + + /* And return the glyph that we found */ + + return glyph; + } + } + return NULL; +} + +/**************************************************************************** + * Name: nxtext_renderglyph + ****************************************************************************/ + +static inline FAR struct nxtext_glyph_s * +nxtext_renderglyph(FAR struct nxtext_state_s *st, + FAR const struct nx_fontbitmap_s *fbm, uint8_t ch) +{ + FAR struct nxtext_glyph_s *glyph = NULL; + FAR nxgl_mxpixel_t *ptr; +#if CONFIG_EXAMPLES_NXTEXT_BPP < 8 + nxgl_mxpixel_t pixel; +#endif + int bmsize; + int row; + int col; + int ret; + + /* Make sure that there is room for another glyph */ + + gvdbg("ch=%c [%02x]\n", isprint(ch) ? ch : '.', ch); + + /* Allocate the glyph (always succeeds) */ + + glyph = nxtext_allocglyph(st); + glyph->code = ch; + + /* Get the dimensions of the glyph */ + + glyph->width = fbm->metric.width + fbm->metric.xoffset; + glyph->height = fbm->metric.height + fbm->metric.yoffset; + + /* Allocate memory to hold the glyph with its offsets */ + + glyph->stride = (glyph->width * CONFIG_EXAMPLES_NXTEXT_BPP + 7) / 8; + bmsize = glyph->stride * glyph->height; + glyph->bitmap = (FAR uint8_t *)malloc(bmsize); + + if (glyph->bitmap) + { + /* Initialize the glyph memory to the background color */ + +#if CONFIG_EXAMPLES_NXTEXT_BPP < 8 + pixel = st->wcolor[0]; +# if CONFIG_EXAMPLES_NXTEXT_BPP == 1 + /* Pack 1-bit pixels into a 2-bits */ + + pixel &= 0x01; + pixel = (pixel) << 1 |pixel; +# endif +# if CONFIG_EXAMPLES_NXTEXT_BPP < 4 + /* Pack 2-bit pixels into a nibble */ + + pixel &= 0x03; + pixel = (pixel) << 2 |pixel; +# endif + + /* Pack 4-bit nibbles into a byte */ + + pixel &= 0x0f; + pixel = (pixel) << 4 | pixel; + + ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; + for (row = 0; row < glyph->height; row++) + { + for (col = 0; col < glyph->stride; col++) + { + /* Transfer the packed bytes into the buffer */ + + *ptr++ = pixel; + } + } + +#elif CONFIG_EXAMPLES_NXTEXT_BPP == 24 +# error "Additional logic is needed here for 24bpp support" + +#else /* CONFIG_EXAMPLES_NXTEXT_BPP = {8,16,32} */ + + ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; + for (row = 0; row < glyph->height; row++) + { + /* Just copy the color value into the glyph memory */ + + for (col = 0; col < glyph->width; col++) + { + *ptr++ = st->wcolor[0]; + } + } +#endif + + /* Then render the glyph into the allocated memory */ + + ret = RENDERER((FAR nxgl_mxpixel_t*)glyph->bitmap, + glyph->height, glyph->width, glyph->stride, + fbm, st->fcolor[0]); + if (ret < 0) + { + /* Actually, the RENDERER never returns a failure */ + + message("nxtext_renderglyph: RENDERER failed\n"); + nxtext_freeglyph(glyph); + glyph = NULL; + } + } + + return glyph; +} + +/**************************************************************************** + * Name: nxtext_fontsize + ****************************************************************************/ + +static int nxtext_fontsize(NXHANDLE hfont, uint8_t ch, FAR struct nxgl_size_s *size) +{ + FAR const struct nx_fontbitmap_s *fbm; + + /* No, it is not cached... Does the code map to a font? */ + + fbm = nxf_getbitmap(hfont, ch); + if (fbm) + { + /* Yes.. return the font size */ + + size->w = fbm->metric.width + fbm->metric.xoffset; + size->h = fbm->metric.height + fbm->metric.yoffset; + return OK; + } + + return ERROR; +} + +/**************************************************************************** + * Name: nxtext_getglyph + ****************************************************************************/ + +static FAR struct nxtext_glyph_s * +nxtext_getglyph(NXHANDLE hfont, FAR struct nxtext_state_s *st, uint8_t ch) +{ + FAR struct nxtext_glyph_s *glyph; + FAR const struct nx_fontbitmap_s *fbm; + + /* First, try to find the glyph in the cache of pre-rendered glyphs */ + + glyph = nxtext_findglyph(st, ch); + if (!glyph) + { + /* No, it is not cached... Does the code map to a font? */ + + fbm = nxf_getbitmap(hfont, ch); + if (fbm) + { + /* Yes.. render the glyph */ + + glyph = nxtext_renderglyph(st, fbm, ch); + } + } + + return glyph; +} + +/**************************************************************************** + * Name: nxtext_addchar + * + * Description: + * This is part of the nxtext_putc logic. It creates and positions a + * the character and renders (or re-uses) a glyph for font. + * + ****************************************************************************/ + +static FAR const struct nxtext_bitmap_s * +nxtext_addchar(NXHANDLE hfont, FAR struct nxtext_state_s *st, uint8_t ch) +{ + FAR struct nxtext_bitmap_s *bm = NULL; + FAR struct nxtext_glyph_s *glyph; + + /* Is there space for another character on the display? */ + + if (st->nchars < st->maxchars) + { + /* Yes, setup the bitmap information */ + + bm = &st->bm[st->nchars]; + bm->code = ch; + bm->flags = 0; + bm->pos.x = st->fpos.x; + bm->pos.y = st->fpos.y; + + /* Find (or create) the matching glyph */ + + glyph = nxtext_getglyph(hfont, st, ch); + if (!glyph) + { + /* No, there is no font for this code. Just mark this as a space. */ + + bm->flags |= BMFLAGS_NOGLYPH; + + /* Set up the next character position */ + + st->fpos.x += st->spwidth; + } + else + { + /* Set up the next character position */ + + st->fpos.x += glyph->width; + } + + /* Success.. increment nchars to retain this character */ + + st->nchars++; + } + + return bm; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxtext_home + * + * Description: + * Set the next character position to the top-left corner of the display. + * + ****************************************************************************/ + +void nxtext_home(FAR struct nxtext_state_s *st) +{ + /* The first character is one space from the left */ + + st->fpos.x = st->spwidth; + + /* And LINE_SEPARATION lines from the top */ + + st->fpos.y = LINE_SEPARATION; +} + +/**************************************************************************** + * Name: nxtext_newline + * + * Description: + * Set the next character position to the beginning of the next line. + * + ****************************************************************************/ + +void nxtext_newline(FAR struct nxtext_state_s *st) +{ + /* Carriage return: The first character is one space from the left */ + + st->fpos.x = st->spwidth; + + /* Linefeed: Down the max font height + LINE_SEPARATION */ + + st->fpos.y += (st->fheight + LINE_SEPARATION); +} + +/**************************************************************************** + * Name: nxtext_putc + * + * Description: + * Render the specified character at the current display position. + * + ****************************************************************************/ + +void nxtext_putc(NXWINDOW hwnd, FAR struct nxtext_state_s *st, NXHANDLE hfont, uint8_t ch) +{ + FAR const struct nxtext_bitmap_s *bm; + + /* If it is a newline character, then just perform the logical newline + * operation. + */ + + if (ch == '\n') + { + nxtext_newline(st); + } + + /* Otherwise, find the glyph associated with the character and render it + * onto the display. + */ + + else + { + bm = nxtext_addchar(hfont, st, ch); + if (bm) + { + nxtext_fillchar(hwnd, NULL, st, hfont, bm); + } + } +} + +/**************************************************************************** + * Name: nxtext_fillchar + * + * Description: + * This implements the character display. It is part of the nxtext_putc + * operation but may also be used when redrawing an existing display. + * + ****************************************************************************/ + +void nxtext_fillchar(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + FAR struct nxtext_state_s *st, + NXHANDLE hfont, FAR const struct nxtext_bitmap_s *bm) +{ + FAR struct nxtext_glyph_s *glyph; + struct nxgl_rect_s bounds; + struct nxgl_rect_s intersection; + struct nxgl_size_s fsize; + int ret; + + /* Handle the special case of spaces which have no glyph bitmap */ + + if (BM_ISSPACE(bm)) + { + return; + } + + /* Get the size of the font glyph (which may not have been created yet) */ + + ret = nxtext_fontsize(hfont, bm->code, &fsize); + if (ret < 0) + { + /* This would mean that there is no bitmap for the character code and + * that the font would be rendered as a space. But this case should + * never happen here because the BM_ISSPACE() should have already + * found all such cases. + */ + + return; + } + + /* Construct a bounding box for the glyph */ + + bounds.pt1.x = bm->pos.x; + bounds.pt1.y = bm->pos.y; + bounds.pt2.x = bm->pos.x + fsize.w - 1; + bounds.pt2.y = bm->pos.y + fsize.h - 1; + + /* Should this also be clipped to a region in the window? */ + + if (rect) + { + /* Get the intersection of the redraw region and the character bitmap */ + + nxgl_rectintersect(&intersection, rect, &bounds); + } + else + { + /* The intersection is the whole glyph */ + + nxgl_rectcopy(&intersection, &bounds); + } + + /* Check for empty intersections */ + + if (!nxgl_nullrect(&intersection)) + { + FAR const void *src; + + /* Find (or create) the glyph that goes with this font */ + + glyph = nxtext_getglyph(hfont, st, bm->code); + if (!glyph) + { + /* Shouldn't happen */ + + return; + } + + /* Blit the font bitmap into the window */ + + src = (FAR const void *)glyph->bitmap; + ret = nx_bitmap((NXWINDOW)hwnd, &intersection, &src, + &bm->pos, (unsigned int)glyph->stride); + if (ret < 0) + { + message("nxtext_fillchar: nx_bitmapwindow failed: %d\n", errno); + } + } +} + diff --git a/apps/examples/nxtext/nxtext_server.c b/apps/examples/nxtext/nxtext_server.c new file mode 100644 index 000000000..2049a3121 --- /dev/null +++ b/apps/examples/nxtext/nxtext_server.c @@ -0,0 +1,194 @@ +/**************************************************************************** + * examples/nxtext/nxtext_server.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sched.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/nx/nx.h> + +#ifdef CONFIG_NX_LCDDRIVER +# include <nuttx/lcd/lcd.h> +#else +# include <nuttx/fb.h> +#endif + +#include "nxtext_internal.h" + +#ifdef CONFIG_NX_MULTIUSER + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxtext_server + ****************************************************************************/ + +int nxtext_server(int argc, char *argv[]) +{ + FAR NX_DRIVERTYPE *dev; + int ret; + +#if defined(CONFIG_EXAMPLES_NXTEXT_EXTERNINIT) + /* Use external graphics driver initialization */ + + message("nxtext_server: Initializing external graphics device\n"); + dev = up_nxdrvinit(CONFIG_EXAMPLES_NXTEXT_DEVNO); + if (!dev) + { + message("nxtext_server: up_nxdrvinit failed, devno=%d\n", CONFIG_EXAMPLES_NXTEXT_DEVNO); + g_exitcode = NXEXIT_EXTINITIALIZE; + return ERROR; + } + +#elif defined(CONFIG_NX_LCDDRIVER) + /* Initialize the LCD device */ + + message("nxtext_server: Initializing LCD\n"); + ret = up_lcdinitialize(); + if (ret < 0) + { + message("nxtext_server: up_lcdinitialize failed: %d\n", -ret); + return 1; + } + + /* Get the device instance */ + + dev = up_lcdgetdev(CONFIG_EXAMPLES_NXTEXT_DEVNO); + if (!dev) + { + message("nxtext_server: up_lcdgetdev failed, devno=%d\n", CONFIG_EXAMPLES_NXTEXT_DEVNO); + return 2; + } + + /* Turn the LCD on at 75% power */ + + (void)dev->setpower(dev, ((3*CONFIG_LCD_MAXPOWER + 3)/4)); +#else + /* Initialize the frame buffer device */ + + message("nxtext_server: Initializing framebuffer\n"); + ret = up_fbinitialize(); + if (ret < 0) + { + message("nxtext_server: up_fbinitialize failed: %d\n", -ret); + return 1; + } + + dev = up_fbgetvplane(CONFIG_EXAMPLES_NXTEXT_VPLANE); + if (!dev) + { + message("nxtext_server: up_fbgetvplane failed, vplane=%d\n", CONFIG_EXAMPLES_NXTEXT_VPLANE); + return 2; + } +#endif + + /* Then start the server */ + + ret = nx_run(dev); + gvdbg("nx_run returned: %d\n", errno); + return 3; +} + +/**************************************************************************** + * Name: nxtext_listener + ****************************************************************************/ + +FAR void *nxtext_listener(FAR void *arg) +{ + int ret; + + /* Process events forever */ + + for (;;) + { + /* Handle the next event. If we were configured blocking, then + * we will stay right here until the next event is received. Since + * we have dedicated a while thread to servicing events, it would + * be most natural to also select CONFIG_NX_BLOCKING -- if not, the + * following would be a tight infinite loop (unless we added addition + * logic with nx_eventnotify and sigwait to pace it). + */ + + ret = nx_eventhandler(g_hnx); + if (ret < 0) + { + /* An error occurred... assume that we have lost connection with + * the server. + */ + + message("nxtext_listener: Lost server connection: %d\n", errno); + exit(NXEXIT_LOSTSERVERCONN); + } + + /* If we received a message, we must be connected */ + + if (!g_connected) + { + g_connected = true; + sem_post(&g_semevent); + message("nxtext_listener: Connected\n"); + } + } +} + +#endif /* CONFIG_NX_MULTIUSER */ diff --git a/apps/examples/ostest/Makefile b/apps/examples/ostest/Makefile new file mode 100644 index 000000000..1405a2afb --- /dev/null +++ b/apps/examples/ostest/Makefile @@ -0,0 +1,133 @@ +############################################################################ +# apps/examples/ostest/Makefile +# +# Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttX OS Test + +ASRCS = +CSRCS = main.c dev_null.c + +ifneq ($(CONFIG_DISABLE_PTHREAD),y) +CSRCS += cancel.c cond.c mutex.c sem.c barrier.c +ifneq ($(CONFIG_RR_INTERVAL),0) +CSRCS += roundrobin.c +endif # CONFIG_RR_INTERVAL +ifeq ($(CONFIG_MUTEX_TYPES),y) +CSRCS += rmutex.c +endif # CONFIG_MUTEX_TYPES +endif # CONFIG_DISABLE_PTHREAD + +ifneq ($(CONFIG_DISABLE_SIGNALS),y) +CSRCS += sighand.c +ifneq ($(CONFIG_DISABLE_PTHREAD),y) +ifneq ($(CONFIG_DISABLE_CLOCK),y) +CSRCS += timedwait.c +endif # CONFIG_DISABLE_CLOCK +endif # CONFIG_DISABLE_PTHREAD +endif # CONFIG_DISABLE_SIGNALS + +ifneq ($(CONFIG_DISABLE_MQUEUE),y) +ifneq ($(CONFIG_DISABLE_PTHREAD),y) +CSRCS += mqueue.c +ifneq ($(CONFIG_DISABLE_CLOCK),y) +CSRCS += timedmqueue.c +endif # CONFIG_DISABLE_CLOCK +endif # CONFIG_DISABLE_PTHREAD +endif # CONFIG_DISABLE_MQUEUE + +ifneq ($(CONFIG_DISABLE_POSIX_TIMERS),y) +CSRCS += posixtimer.c +endif + +ifneq ($(CONFIG_DISABLE_SIGNALS),y) +ifneq ($(CONFIG_DISABLE_PTHREAD),y) +ifeq ($(CONFIG_PRIORITY_INHERITANCE),y) +CSRCS += prioinherit.c +endif # CONFIG_PRIORITY_INHERITANCE +endif # CONFIG_DISABLE_PTHREAD +endif # CONFIG_DISABLE_SIGNALS + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/ostest/barrier.c b/apps/examples/ostest/barrier.c new file mode 100644 index 000000000..da1301dc3 --- /dev/null +++ b/apps/examples/ostest/barrier.c @@ -0,0 +1,208 @@ +/**************************************************************************** + * examples/ostest/barrier.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> + +#include "ostest.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define HALF_SECOND 500000L + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static pthread_barrier_t barrier; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: barrier_func + ****************************************************************************/ + +static void *barrier_func(void *parameter) +{ + int id = (int)parameter; + int status; + + printf("barrier_func: Thread %d started\n", id); +#ifndef CONFIG_DISABLE_SIGNALS + usleep(HALF_SECOND); +#endif + + /* Wait at the barrier until all threads are synchronized. */ + + printf("barrier_func: Thread %d calling pthread_barrier_wait()\n", + id); + FFLUSH(); + status = pthread_barrier_wait(&barrier); + if (status == 0) + { + printf("barrier_func: Thread %d, back with " + "status=0 (I am not special)\n", + id, status); + } + else if (status == PTHREAD_BARRIER_SERIAL_THREAD) + { + printf("barrier_func: Thread %d, back with " + "status=PTHREAD_BARRIER_SERIAL_THREAD (I AM SPECIAL)\n", + id, status); + } + else + { + printf("barrier_func: ERROR thread %d could not get semaphore value\n", + id); + } + FFLUSH(); + +#ifndef CONFIG_DISABLE_SIGNALS + usleep(HALF_SECOND); +#endif + printf("barrier_func: Thread %d done\n", id); + FFLUSH(); + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: barrier_test + ****************************************************************************/ + +void barrier_test(void) +{ + pthread_t barrier_thread[CONFIG_EXAMPLES_OSTEST_NBARRIER_THREADS]; + pthread_addr_t result; + pthread_attr_t attr; + pthread_barrierattr_t barrierattr; + int status; + int i; + + printf("barrier_test: Initializing barrier\n"); + + status = pthread_barrierattr_init(&barrierattr); + if (status != OK) + { + printf("barrier_test: pthread_barrierattr_init failed, status=%d\n", + status); + } + + status = pthread_barrier_init(&barrier, &barrierattr, + CONFIG_EXAMPLES_OSTEST_NBARRIER_THREADS); + if (status != OK) + { + printf("barrier_test: pthread_barrierattr_init failed, status=%d\n", + status); + } + + /* Create the barrier */ + + status = pthread_barrierattr_init(&barrierattr); + + /* Start CONFIG_EXAMPLES_OSTEST_NBARRIER_THREADS thread instances */ + + status = pthread_attr_init(&attr); + if (status != OK) + { + printf("barrier_test: pthread_attr_init failed, status=%d\n", + status); + } + + for (i = 0; i < CONFIG_EXAMPLES_OSTEST_NBARRIER_THREADS; i++) + { + status = pthread_create(&barrier_thread[i], &attr, barrier_func, + (pthread_addr_t)i); + if (status != 0) + { + printf("barrier_test: Error in thread %d create, status=%d\n", + i, status); + printf("barrier_test: Test aborted with waiting threads\n"); + goto abort_test; + } + else + { + printf("barrier_test: Thread %d created\n", i); + } + } + FFLUSH(); + + /* Wait for all thread instances to complete */ + + for (i = 0; i < CONFIG_EXAMPLES_OSTEST_NBARRIER_THREADS; i++) + { + status = pthread_join(barrier_thread[i], &result); + if (status != 0) + { + printf("barrier_test: Error in thread %d join, status=%d\n", + i, status); + } + else + { + printf("barrier_test: Thread %d completed with result=%p\n", + i, result); + } + } + + /* Destroy the barrier */ + +abort_test: + status = pthread_barrier_destroy(&barrier); + if (status != OK) + { + printf("barrier_test: pthread_barrier_destroy failed, status=%d\n", + status); + } + + status = pthread_barrierattr_destroy(&barrierattr); + if (status != OK) + { + printf("barrier_test: pthread_barrierattr_destroy failed, status=%d\n", + status); + } + FFLUSH(); +} diff --git a/apps/examples/ostest/cancel.c b/apps/examples/ostest/cancel.c new file mode 100644 index 000000000..bf2d03615 --- /dev/null +++ b/apps/examples/ostest/cancel.c @@ -0,0 +1,333 @@ +/*********************************************************************** + * examples/ostest/cancel.c + * + * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ***********************************************************************/ + +#include <stdio.h> +#include <time.h> +#include <pthread.h> +#include <errno.h> +#include "ostest.h" + +static pthread_mutex_t mutex; +static pthread_cond_t cond; + +static void *thread_waiter(void *parameter) +{ + int status; + + /* Take the mutex */ + + printf("thread_waiter: Taking mutex\n"); + status = pthread_mutex_lock(&mutex); + if (status != 0) + { + printf("thread_waiter: ERROR pthread_mutex_lock failed, status=%d\n", status); + } + + printf("thread_waiter: Starting wait for condition\n"); + + /* Are we a non-cancelable thread? Yes, set the non-cancelable state */ + + if (!parameter) + { + printf("thread_waiter: Setting non-cancelable\n"); + status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + if (status != 0) + { + printf("thread_waiter: ERROR pthread_setcancelstate failed, status=%d\n", status); + } + } + + /* The wait -- we will never awaken from this. */ + + status = pthread_cond_wait(&cond, &mutex); + if (status != 0) + { + printf("thread_waiter: ERROR pthread_cond_wait failed, status=%d\n", status); + } + + /* Release the mutex */ + + printf("thread_waiter: Releasing mutex\n"); + status = pthread_mutex_unlock(&mutex); + if (status != 0) + { + printf("thread_waiter: ERROR pthread_mutex_unlock failed, status=%d\n", status); + } + + /* Set the cancelable state */ + + printf("thread_waiter: Setting cancelable\n"); + status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + if (status != 0) + { + printf("thread_waiter: ERROR pthread_setcancelstate failed, status=%d\n", status); + } + + printf("thread_waiter: Exit with status 0x12345678\n"); + pthread_exit((pthread_addr_t)0x12345678); + return NULL; +} + +static void start_thread(pthread_t *waiter, int cancelable) +{ + pthread_attr_t attr; + int status; + + /* Initialize the mutex */ + + printf("start_thread: Initializing mutex\n"); + status = pthread_mutex_init(&mutex, NULL); + if (status != 0) + { + printf("start_thread: ERROR pthread_mutex_init failed, status=%d\n", status); + } + + /* Initialize the condition variable */ + + printf("start_thread: Initializing cond\n"); + status = pthread_cond_init(&cond, NULL); + if (status != 0) + { + printf("start_thread: ERROR pthread_cond_init failed, status=%d\n", status); + } + + /* Set up attributes */ + + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("start_thread: pthread_attr_init failed, status=%d\n", status); + } + + status = pthread_attr_setstacksize(&attr, STACKSIZE); + if (status != 0) + { + printf("start_thread: pthread_attr_setstacksize failed, status=%d\n", status); + } + + /* Start the waiter thread */ + + printf("start_thread: Starting thread\n"); + status = pthread_create(waiter, &attr, thread_waiter, (pthread_addr_t)cancelable); + if (status != 0) + { + printf("start_thread: ERROR pthread_create failed, status=%d\n", status); + } + + /* Make sure that the waiter thread gets a chance to run */ + + printf("start_thread: Yielding\n"); + pthread_yield(); +} + +static void restart_thread(pthread_t *waiter, int cancelable) +{ + int status; + + /* Destroy the condition variable */ + + printf("restart_thread: Destroying cond\n"); + status = pthread_cond_destroy(&cond); + if (status != 0) + { + printf("restart_thread: ERROR pthread_cond_destroy failed, status=%d\n", status); + } + + /* Destroy the mutex */ + + printf("restart_thread: Destroying mutex\n"); + status = pthread_cond_destroy(&cond); + if (status != 0) + { + printf("restart_thread: ERROR pthread_mutex_destroy failed, status=%d\n", status); + } + + /* Then restart the thread */ + + printf("restart_thread: Re-starting thread\n"); + start_thread(waiter, cancelable); +} + +void cancel_test(void) +{ + pthread_t waiter; + void *result; + int status; + + /* Test 1: Normal Cancel *********************************************/ + /* Start the waiter thread */ + + printf("cancel_test: Test 1: Normal Cancelation\n"); + printf("cancel_test: Starting thread\n"); + start_thread(&waiter, 1); + + /* Then cancel it. It should be in the pthread_cond_wait now */ + + printf("cancel_test: Canceling thread\n"); + status = pthread_cancel(waiter); + if (status != 0) + { + printf("cancel_test: ERROR pthread_cancel failed, status=%d\n", status); + } + + /* Then join to the thread to pick up the result (if we don't do + * we will have a memory leak!) + */ + + printf("cancel_test: Joining\n"); + status = pthread_join(waiter, &result); + if (status != 0) + { + printf("cancel_test: ERROR pthread_join failed, status=%d\n", status); + } + else + { + printf("cancel_test: waiter exited with result=%p\n", result); + if (result != PTHREAD_CANCELED) + { + printf("cancel_test: ERROR expected result=%p\n", PTHREAD_CANCELED); + } + else + { + printf("cancel_test: PASS thread terminated with PTHREAD_CANCELED\n"); + } + } + + /* Test 2: Cancel Detached Thread ************************************/ + + printf("cancel_test: Test 2: Cancelation of detached thread\n"); + printf("cancel_test: Re-starting thread\n"); + restart_thread(&waiter, 1); + + /* Detach the thread */ + + status = pthread_detach(waiter); + if (status != 0) + { + printf("cancel_test: ERROR pthread_detach, status=%d\n", status); + } + + /* Then cancel it. It should be in the pthread_cond_wait now */ + + printf("cancel_test: Canceling thread\n"); + status = pthread_cancel(waiter); + if (status != 0) + { + printf("cancel_test: ERROR pthread_cancel failed, status=%d\n", status); + } + + /* Join should now fail */ + + printf("cancel_test: Joining\n"); + status = pthread_join(waiter, &result); + if (status == 0) + { + printf("cancel_test: ERROR pthread_join succeeded\n"); + } + else if (status != ESRCH) + { + printf("cancel_test: ERROR pthread_join failed but with wrong status=%d\n", status); + } + else + { + printf("cancel_test: PASS pthread_join failed with status=ESRCH\n"); + } + + /* Test 3: Non-cancelable threads ************************************/ + + printf("cancel_test: Test 3: Non-cancelable threads\n"); + printf("cancel_test: Re-starting thread (non-cancelable)\n"); + restart_thread(&waiter, 0); + + /* Then cancel it. It should be in the pthread_cond_wait now. The + * behavior here is non-standard: when the thread is at a cancelation + * point, it should be cancelable, even when cancelation is disable. + * + * The cancelation should succeed, because the cancelation is pending. + */ + + printf("cancel_test: Canceling thread\n"); + status = pthread_cancel(waiter); + if (status != 0) + { + printf("cancel_test: ERROR pthread_cancel failed, status=%d\n", status); + } + + /* Signal the thread. It should wake up and restore the cancelable state. + * When the cancelable state is re-enabled, the thread should be canceled. + */ + + status = pthread_mutex_lock(&mutex); + if (status != 0) + { + printf("cancel_test: ERROR pthread_mutex_lock failed, status=%d\n", status); + } + + status = pthread_cond_signal(&cond); + if (status != 0) + { + printf("cancel_test: ERROR pthread_cond_signal failed, status=%d\n", status); + } + + status = pthread_mutex_unlock(&mutex); + if (status != 0) + { + printf("cancel_test: ERROR pthread_mutex_unlock failed, status=%d\n", status); + } + + /* Then join to the thread to pick up the result (if we don't do + * we will have a memory leak!) + */ + + printf("cancel_test: Joining\n"); + status = pthread_join(waiter, &result); + if (status != 0) + { + printf("cancel_test: ERROR pthread_join failed, status=%d\n", status); + } + else + { + printf("cancel_test: waiter exited with result=%p\n", result); + if (result != PTHREAD_CANCELED) + { + printf("cancel_test: ERROR expected result=%p\n", PTHREAD_CANCELED); + } + else + { + printf("cancel_test: PASS thread terminated with PTHREAD_CANCELED\n"); + } + } + +} diff --git a/apps/examples/ostest/cond.c b/apps/examples/ostest/cond.c new file mode 100644 index 000000000..11191b7d5 --- /dev/null +++ b/apps/examples/ostest/cond.c @@ -0,0 +1,294 @@ +/*********************************************************************** + * cond.c + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ***********************************************************************/ + +#include <stdio.h> +#include <pthread.h> +#include <unistd.h> +#include "ostest.h" + +#ifndef NULL +# define NULL (void*)0 +#endif + +static volatile enum { RUNNING, MUTEX_WAIT, COND_WAIT} waiter_state; + +static pthread_mutex_t mutex; +static pthread_cond_t cond; +static volatile int data_available = 0; +static int waiter_nloops = 0; +static int waiter_waits = 0; +static int waiter_nerrors = 0; +static int signaler_nloops = 0; +static int signaler_already = 0; +static int signaler_state = 0; +static int signaler_nerrors = 0; + +static void *thread_waiter(void *parameter) +{ + int status; + + printf("waiter_thread: Started\n"); + + for(;;) + { + /* Take the mutex */ + + waiter_state = MUTEX_WAIT; + status = pthread_mutex_lock(&mutex); + waiter_state = RUNNING; + + if (status != 0) + { + printf("waiter_thread: ERROR pthread_mutex_lock failed, status=%d\n", status); + waiter_nerrors++; + } + + /* Check if data is available -- if data is not available then + * wait for it + */ + + if (!data_available) + { + /* We are higher priority than the signaler thread so the + * only time that the signaler thread will have a chance to run is when + * we are waiting for the condition variable. In this case, pthread_cond_wait + * will automatically release the mutex for the signaler (then re-acquire + * the mutex before returning. + */ + + waiter_state = COND_WAIT; + status = pthread_cond_wait(&cond, &mutex); + waiter_state = RUNNING; + + if (status != 0) + { + printf("waiter_thread: ERROR pthread_cond_wait failed, status=%d\n", status); + waiter_nerrors++; + } + waiter_waits++; + } + + /* Now data should be available */ + + if (!data_available) + { + printf("waiter_thread: ERROR data not available after wait\n"); + waiter_nerrors++; + } + + /* Clear data available */ + + data_available = 0; + + /* Release the mutex */ + + status = pthread_mutex_unlock(&mutex); + if (status != 0) + { + printf("waiter_thread: ERROR waiter: pthread_mutex_unlock failed, status=%d\n", status); + waiter_nerrors++; + } + + waiter_nloops++; + } + return NULL; +} + +static void *thread_signaler(void *parameter) +{ + int status; + int i; + + printf("thread_signaler: Started\n"); + for (i = 0; i < 32; i++) + { + /* Take the mutex. The waiter is higher priority and should + * run until it waits for the condition. So, at this point + * signaler should be waiting for the condition. + */ + + status = pthread_mutex_lock(&mutex); + if (status != 0) + { + printf("thread_signaler: ERROR pthread_mutex_lock failed, status=%d\n", status); + signaler_nerrors++; + } + + /* Verify the state */ + + if (waiter_state != COND_WAIT) + { + printf("thread_signaler: ERROR waiter state = %d != COND_WAITING\n", waiter_state); + signaler_state++; + } + + if (data_available) + { + printf("thread_signaler: ERROR data already available, waiter_state=%d\n", waiter_state); + signaler_already++; + } + + /* Set data available and signal the waiter */ + + data_available = 1; + status = pthread_cond_signal(&cond); + if (status != 0) + { + printf("thread_signaler: ERROR pthread_cond_signal failed, status=%d\n", status); + signaler_nerrors++; + } + + /* Release the mutex */ + + status = pthread_mutex_unlock(&mutex); + if (status != 0) + { + printf("thread_signaler: ERROR pthread_mutex_unlock failed, status=%d\n", status); + signaler_nerrors++; + } + + signaler_nloops++; + } + + printf("thread_signaler: Terminating\n"); + pthread_exit(NULL); + return NULL; /* Non-reachable -- needed for some compilers */ +} + +void cond_test(void) +{ + pthread_t waiter; + pthread_t signaler; + pthread_attr_t attr; +#ifdef SDCC + pthread_addr_t result; +#endif + struct sched_param sparam; + int prio_min; + int prio_max; + int prio_mid; + int status; + + /* Initialize the mutex */ + + printf("cond_test: Initializing mutex\n"); + status = pthread_mutex_init(&mutex, NULL); + if (status != 0) + { + printf("cond_test: ERROR pthread_mutex_init failed, status=%d\n", status); + } + + /* Initialize the condition variable */ + + printf("cond_test: Initializing cond\n"); + status = pthread_cond_init(&cond, NULL); + if (status != 0) + { + printf("cond_test: ERROR pthread_condinit failed, status=%d\n", status); + } + + /* Start the waiter thread at higher priority */ + + printf("cond_test: Starting waiter\n"); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("cond_test: pthread_attr_init failed, status=%d\n", status); + } + + prio_min = sched_get_priority_min(SCHED_FIFO); + prio_max = sched_get_priority_max(SCHED_FIFO); + prio_mid = (prio_min + prio_max) / 2; + + sparam.sched_priority = prio_mid; + status = pthread_attr_setschedparam(&attr,&sparam); + if (status != OK) + { + printf("cond_test: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("cond_test: Set thread 1 priority to %d\n", sparam.sched_priority); + } + + status = pthread_create(&waiter, &attr, thread_waiter, NULL); + if (status != 0) + { + printf("cond_test: pthread_create failed, status=%d\n", status); + } + + printf("cond_test: Starting signaler\n"); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("cond_test: pthread_attr_init failed, status=%d\n", status); + } + + sparam.sched_priority = (prio_min + prio_mid) / 2; + status = pthread_attr_setschedparam(&attr,&sparam); + if (status != OK) + { + printf("cond_test: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("cond_test: Set thread 2 priority to %d\n", sparam.sched_priority); + } + + status = pthread_create(&signaler, &attr, thread_signaler, NULL); + if (status != 0) + { + printf("cond_test: pthread_create failed, status=%d\n", status); + } + + /* Wait for the threads to stop */ + +#ifdef SDCC + pthread_join(signaler, &result); +#else + pthread_join(signaler, NULL); +#endif + printf("cond_test: signaler terminated, now cancel the waiter\n"); + pthread_detach(waiter); + pthread_cancel(waiter); + + printf("cond_test: \tWaiter\tSignaler\n"); + printf("cond_test: Loops\t%d\t%d\n", waiter_nloops, signaler_nloops); + printf("cond_test: Errors\t%d\t%d\n", waiter_nerrors, signaler_nerrors); + printf("cond_test:\n"); + printf("cond_test: %d times, waiter did not have to wait for data\n", waiter_nloops - waiter_waits); + printf("cond_test: %d times, data was already available when the signaler run\n", signaler_already); + printf("cond_test: %d times, the waiter was in an unexpected state when the signaler ran\n", signaler_state); +} diff --git a/apps/examples/ostest/dev_null.c b/apps/examples/ostest/dev_null.c new file mode 100644 index 000000000..e8fc6cf3f --- /dev/null +++ b/apps/examples/ostest/dev_null.c @@ -0,0 +1,92 @@ +/**************************************************************************** + * examples/ostest/dev_null.c + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include "ostest.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 + +static FAR char buffer[1024]; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int dev_null(void) +{ + int nbytes; + int fd; + + fd = open("/dev/null", O_RDWR); + if (fd < 0) + { + printf("dev_null: ERROR Failed to open /dev/null\n"); + return -1; + } + + nbytes = read(fd, buffer, 1024); + if (nbytes < 0) + { + printf("dev_null: ERROR Failed to read from /dev/null\n"); + close(fd); + return -1; + } + printf("dev_null: Read %d bytes from /dev/null\n", nbytes); + + nbytes = write(fd, buffer, 1024); + if (nbytes < 0) + { + printf("dev_null: ERROR Failed to write to /dev/null\n"); + close(fd); + return -1; + } + printf("dev_null: Wrote %d bytes to /dev/null\n", nbytes); + + close(fd); + return 0; +} + +#endif /*CONFIG_NFILE_DESCRIPTORS */ diff --git a/apps/examples/ostest/main.c b/apps/examples/ostest/main.c new file mode 100644 index 000000000..327ec60e1 --- /dev/null +++ b/apps/examples/ostest/main.c @@ -0,0 +1,514 @@ +/**************************************************************************** + * examples/ostest/main.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sched.h> +#include <nuttx/init.h> + +#include "ostest.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define PRIORITY 100 +#define NARGS 4 +#define HALF_SECOND_USEC 500000L + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char arg1[] = "Arg1"; +static const char arg2[] = "Arg2"; +static const char arg3[] = "Arg3"; +static const char arg4[] = "Arg4"; + +#if CONFIG_NFILE_DESCRIPTORS > 0 +static const char write_data1[] = "stdio_test: write fd=1\n"; +static const char write_data2[] = "stdio_test: write fd=2\n"; +#endif + +#ifdef SDCC +/* I am not yet certain why SDCC does not like the following + * initializer. It involves some issues with 2- vs 3-byte + * pointer types. + */ + +static const char *g_argv[NARGS+1]; +#else +static const char *g_argv[NARGS+1] = { arg1, arg2, arg3, arg4, NULL }; +#endif + +#ifndef CONFIG_DISABLE_SIGNALS +static struct mallinfo g_mmbefore; +static struct mallinfo g_mmprevious; +static struct mallinfo g_mmafter; +#endif + +#ifndef CONFIG_DISABLE_ENVIRON +const char g_var1_name[] = "Variable1"; +const char g_var1_value[] = "GoodValue1"; +const char g_var2_name[] = "Variable2"; +const char g_var2_value[] = "GoodValue2"; +const char g_var3_name[] = "Variable3"; +const char g_var3_value[] = "GoodValue3"; + +const char g_bad_value1[] = "BadValue1"; +const char g_bad_value2[] = "BadValue2"; + +const char g_putenv_value[] = "Variable1=BadValue3"; + +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: show_memory_usage + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_SIGNALS +static void show_memory_usage(struct mallinfo *mmbefore, + struct mallinfo *mmafter) +{ + printf("VARIABLE BEFORE AFTER\n"); + printf("======== ======== ========\n"); + printf("arena %8x %8x\n", mmbefore->arena, mmafter->arena); + printf("ordblks %8d %8d\n", mmbefore->ordblks, mmafter->ordblks); + printf("mxordblk %8x %8x\n", mmbefore->mxordblk, mmafter->mxordblk); + printf("uordblks %8x %8x\n", mmbefore->uordblks, mmafter->uordblks); + printf("fordblks %8x %8x\n", mmbefore->fordblks, mmafter->fordblks); +} +#else +# define show_memory_usage(mm1, mm2) +#endif + +/**************************************************************************** + * Name: check_test_memory_usage + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_SIGNALS +static void check_test_memory_usage(void) +{ + /* Wait a little bit to let any threads terminate */ + + usleep(HALF_SECOND_USEC); + + /* Get the current memory usage */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmafter = mallinfo(); +#else + (void)mallinfo(&g_mmafter); +#endif + + /* Show the change from the previous time */ + + printf("\nEnd of test memory usage:\n"); + show_memory_usage(&g_mmprevious, &g_mmafter); + + /* Set up for the next test */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmprevious = g_mmafter; +#else + memcpy(&g_mmprevious, &g_mmafter, sizeof(struct mallinfo)); +#endif + + /* If so enabled, show the use of priority inheritance resources */ + + dump_nfreeholders("user_main:"); +} +#else +# define check_test_memory_usage() +#endif + +/**************************************************************************** + * Name: show_variable + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_ENVIRON +static void show_variable(const char *var_name, const char *exptd_value, bool var_valid) +{ + char *actual_value = getenv(var_name); + if (actual_value) + { + if (var_valid) + { + if (strcmp(actual_value, exptd_value) == 0) + { + printf("show_variable: Variable=%s has value=%s\n", var_name, exptd_value); + } + else + { + printf("show_variable: ERROR Variable=%s has the wrong value\n", var_name); + printf("show_variable: found=%s expected=%s\n", actual_value, exptd_value); + } + } + else + { + printf("show_variable: ERROR Variable=%s has a value when it should not\n", var_name); + printf("show_variable: value=%s\n", actual_value); + } + } + else if (var_valid) + { + printf("show_variable: ERROR Variable=%s has no value\n", var_name); + printf("show_variable: Should have had value=%s\n", exptd_value); + } + else + { + printf("show_variable: Variable=%s has no value\n", var_name); + } +} + +static void show_environment(bool var1_valid, bool var2_valid, bool var3_valid) +{ + show_variable(g_var1_name, g_var1_value, var1_valid); + show_variable(g_var2_name, g_var2_value, var2_valid); + show_variable(g_var3_name, g_var3_value, var3_valid); +} +#else +# define show_environment() +#endif + +/**************************************************************************** + * Name: user_main + ****************************************************************************/ + +static int user_main(int argc, char *argv[]) +{ + int i; + + /* Sample the memory usage now */ + +#ifndef CONFIG_DISABLE_SIGNALS + usleep(HALF_SECOND_USEC); + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmbefore = mallinfo(); + g_mmprevious = g_mmbefore; +#else + (void)mallinfo(&g_mmbefore); + memcpy(&g_mmprevious, &g_mmbefore, sizeof(struct mallinfo)); +#endif +#endif + + printf("\nuser_main: Begin argument test\n"); + printf("user_main: Started with argc=%d\n", argc); + + /* Verify passed arguments */ + + if (argc != NARGS + 1) + { + printf("user_main: Error expected argc=%d got argc=%d\n", + NARGS+1, argc); + } + + for (i = 0; i <= NARGS; i++) + { + printf("user_main: argv[%d]=\"%s\"\n", i, argv[i]); + } + + for (i = 1; i <= NARGS; i++) + { + if (strcmp(argv[i], g_argv[i-1]) != 0) + { + printf("user_main: ERROR argv[%d]: Expected \"%s\" found \"%s\"\n", + i, g_argv[i-1], argv[i]); + } + } + check_test_memory_usage(); + + /* Check environment variables */ +#ifndef CONFIG_DISABLE_ENVIRON + show_environment(true, true, true); + + unsetenv(g_var1_name); + show_environment(false, true, true); + check_test_memory_usage(); + + clearenv(); + show_environment(false, false, false); + check_test_memory_usage(); +#endif + + /* Top of test loop */ + +#if CONFIG_EXAMPLES_OSTEST_LOOPS > 1 + for (i = 0; i < CONFIG_EXAMPLES_OSTEST_LOOPS; i++) +#elif CONFIG_EXAMPLES_OSTEST_LOOPS == 0 + for (;;) +#endif + { +#if CONFIG_NFILE_DESCRIPTORS > 0 + /* Checkout /dev/null */ + + printf("\nuser_main: /dev/null test\n"); + dev_null(); + check_test_memory_usage(); +#endif + +#ifndef CONFIG_DISABLE_PTHREAD + /* Verify pthreads and pthread mutex */ + + printf("\nuser_main: mutex test\n"); + mutex_test(); + check_test_memory_usage(); +#endif + +#if !defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_MUTEX_TYPES) + /* Verify recursive mutexes */ + + printf("\nuser_main: recursive mutex test\n"); + recursive_mutex_test(); + check_test_memory_usage(); +#endif + +#ifndef CONFIG_DISABLE_PTHREAD + /* Verify pthread cancellation */ + + printf("\nuser_main: cancel test\n"); + cancel_test(); + check_test_memory_usage(); +#endif + +#ifndef CONFIG_DISABLE_PTHREAD + /* Verify pthreads and semaphores */ + + printf("\nuser_main: semaphore test\n"); + sem_test(); + check_test_memory_usage(); +#endif + +#ifndef CONFIG_DISABLE_PTHREAD + /* Verify pthreads and condition variables */ + + printf("\nuser_main: condition variable test\n"); +#ifdef CONFIG_PRIORITY_INHERITANCE + printf("\n Skipping, Test logic incompatible with priority inheritance\n"); +#else + cond_test(); + check_test_memory_usage(); +#endif +#endif + +#if !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_PTHREAD) && !defined(CONFIG_DISABLE_CLOCK) + /* Verify pthreads and condition variable timed waits */ + + printf("\nuser_main: timed wait test\n"); + timedwait_test(); + check_test_memory_usage(); +#endif + +#if !defined(CONFIG_DISABLE_MQUEUE) && !defined(CONFIG_DISABLE_PTHREAD) + /* Verify pthreads and message queues */ + + printf("\nuser_main: message queue test\n"); + mqueue_test(); + check_test_memory_usage(); +#endif + +#if !defined(CONFIG_DISABLE_MQUEUE) && !defined(CONFIG_DISABLE_PTHREAD) && !defined(CONFIG_DISABLE_CLOCK) + /* Verify pthreads and message queues */ + + printf("\nuser_main: timed message queue test\n"); + timedmqueue_test(); + check_test_memory_usage(); +#endif + +#ifndef CONFIG_DISABLE_SIGNALS + /* Verify signal handlers */ + + printf("\nuser_main: signal handler test\n"); + sighand_test(); + check_test_memory_usage(); +#endif + +#if !defined(CONFIG_DISABLE_POSIX_TIMERS) && !defined(CONFIG_DISABLE_SIGNALS) + /* Verify posix timers */ + + printf("\nuser_main: POSIX timer test\n"); + timer_test(); + check_test_memory_usage(); +#endif + +#if !defined(CONFIG_DISABLE_PTHREAD) && CONFIG_RR_INTERVAL > 0 + /* Verify round robin scheduling */ + + printf("\nuser_main: round-robin scheduler test\n"); + rr_test(); + check_test_memory_usage(); +#endif + +#ifndef CONFIG_DISABLE_PTHREAD + /* Verify pthread barriers */ + + printf("\nuser_main: barrier test\n"); + barrier_test(); + check_test_memory_usage(); +#endif + +#if defined(CONFIG_PRIORITY_INHERITANCE) && !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_PTHREAD) + /* Verify priority inheritance */ + + printf("\nuser_main: priority inheritance test\n"); + priority_inheritance(); + check_test_memory_usage(); +#endif /* CONFIG_PRIORITY_INHERITANCE && !CONFIG_DISABLE_SIGNALS && !CONFIG_DISABLE_PTHREAD */ + + /* Compare memory usage at time user_start started until + * user_main exits. These should not be identical, but should + * be similar enough that we can detect any serious OS memory + * leaks. + */ + +#ifndef CONFIG_DISABLE_SIGNALS + usleep(HALF_SECOND_USEC); + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_mmafter = mallinfo(); +#else + (void)mallinfo(&g_mmafter); +#endif + + printf("\nFinal memory usage:\n"); + show_memory_usage(&g_mmbefore, &g_mmafter); +#endif + } + printf("user_main: Exitting\n"); + return 0; +} + +/**************************************************************************** + * Name: stdio_test + ****************************************************************************/ + +static void stdio_test(void) +{ + /* Verify that we can communicate */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 + write(1, write_data1, sizeof(write_data1)-1); +#endif + printf("stdio_test: Standard I/O Check: printf\n"); + +#if CONFIG_NFILE_DESCRIPTORS > 1 + write(2, write_data2, sizeof(write_data2)-1); +#endif +#if CONFIG_NFILE_STREAMS > 0 + fprintf(stderr, "stdio_test: Standard I/O Check: fprintf to stderr\n"); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + int result; + + /* Verify that stdio works first */ + + stdio_test(); + +#ifdef SDCC + /* I am not yet certain why SDCC does not like the following initilizers. + * It involves some issues with 2- vs 3-byte pointer types. + */ + + g_argv[0] = arg1; + g_argv[1] = arg2; + g_argv[2] = arg3; + g_argv[3] = arg4; + g_argv[4] = NULL; +#endif + + /* Set up some environment variables */ + +#ifndef CONFIG_DISABLE_ENVIRON + printf("user_start: putenv(%s)\n", g_putenv_value); + putenv(g_putenv_value); /* Varaible1=BadValue3 */ + printf("user_start: setenv(%s, %s, TRUE)\n", g_var1_name, g_var1_value); + setenv(g_var1_name, g_var1_value, TRUE); /* Variable1=GoodValue1 */ + + printf("user_start: setenv(%s, %s, FALSE)\n", g_var2_name, g_bad_value1); + setenv(g_var2_name, g_bad_value1, FALSE); /* Variable2=BadValue1 */ + printf("user_start: setenv(%s, %s, TRUE)\n", g_var2_name, g_var2_value); + setenv(g_var2_name, g_var2_value, TRUE); /* Variable2=GoodValue2 */ + + printf("user_start: setenv(%s, %s, FALSE)\n", g_var3_name, g_var3_name); + setenv(g_var3_name, g_var3_value, FALSE); /* Variable3=GoodValue3 */ + printf("user_start: setenv(%s, %s, FALSE)\n", g_var3_name, g_var3_name); + setenv(g_var3_name, g_bad_value2, FALSE); /* Variable3=GoodValue3 */ + show_environment(true, true, true); +#endif + + /* Verify that we can spawn a new task */ + +#ifndef CONFIG_CUSTOM_STACK + result = task_create("ostest", PRIORITY, STACKSIZE, user_main, g_argv); +#else + result = task_create("ostest", PRIORITY, user_main, g_argv); +#endif + if (result == ERROR) + { + printf("user_start: ERROR Failed to start user_main\n"); + } + else + { + printf("user_start: Started user_main at PID=%d\n", result); + } + + printf("user_start: Exitting\n"); + return 0; +} diff --git a/apps/examples/ostest/mqueue.c b/apps/examples/ostest/mqueue.c new file mode 100644 index 000000000..95e6bbfc8 --- /dev/null +++ b/apps/examples/ostest/mqueue.c @@ -0,0 +1,394 @@ +/************************************************************************** + * apps/examples/ostest/mqueue.c + * + * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/************************************************************************** + * Included Files + **************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <pthread.h> +#include <mqueue.h> +#include <sched.h> +#include <errno.h> + +#include "ostest.h" + +/************************************************************************** + * Private Definitions + **************************************************************************/ + +#define TEST_MESSAGE "This is a test and only a test" +#if defined(SDCC) || defined(__ZILOG__) + /* Cannot use strlen in array size */ + +# define TEST_MSGLEN (31) +#else + /* Message lenght is the size of the message plus the null terminator */ + +# define TEST_MSGLEN (strlen(TEST_MESSAGE)+1) +#endif + +#define TEST_SEND_NMSGS (10) +#ifndef CONFIG_DISABLE_SIGNALS +# define TEST_RECEIVE_NMSGS (11) +#else +# define TEST_RECEIVE_NMSGS (10) +#endif + +#define HALF_SECOND_USEC_USEC 500000L + +/************************************************************************** + * Private Types + **************************************************************************/ + +/************************************************************************** + * Private Function Prototypes + **************************************************************************/ + +/************************************************************************** + * Global Variables + **************************************************************************/ + +/************************************************************************** + * Private Variables + **************************************************************************/ + +/************************************************************************** + * Private Functions + **************************************************************************/ + +/************************************************************************** + * Public Functions + **************************************************************************/ + +static void *sender_thread(void *arg) +{ + mqd_t mqfd; + char msg_buffer[TEST_MSGLEN]; + struct mq_attr attr; + int status = 0; + int nerrors = 0; + int i; + + printf("sender_thread: Starting\n"); + + /* Fill in attributes for message queue */ + + attr.mq_maxmsg = 20; + attr.mq_msgsize = TEST_MSGLEN; + attr.mq_flags = 0; + + /* Set the flags for the open of the queue. + * Make it a blocking open on the queue, meaning it will block if + * this process tries to send to the queue and the queue is full. + * + * O_CREAT - the queue will get created if it does not already exist. + * O_WRONLY - we are only planning to write to the queue. + * + * Open the queue, and create it if the receiving process hasn't + * already created it. + */ + + mqfd = mq_open("testmq", O_WRONLY|O_CREAT, 0666, &attr); + if (mqfd < 0) + { + printf("sender_thread: ERROR mq_open failed\n"); + pthread_exit((pthread_addr_t)1); + } + + /* Fill in a test message buffer to send */ + + memcpy(msg_buffer, TEST_MESSAGE, TEST_MSGLEN); + + /* Perform the send TEST_SEND_NMSGS times */ + + for (i = 0; i < TEST_SEND_NMSGS; i++) + { + status = mq_send(mqfd, msg_buffer, TEST_MSGLEN, 42); + if (status < 0) + { + printf("sender_thread: ERROR mq_send failure=%d on msg %d\n", status, i); + nerrors++; + } + else + { + printf("sender_thread: mq_send succeeded on msg %d\n", i); + } + } + + /* Close the queue and return success */ + + if (mq_close(mqfd) < 0) + { + printf("sender_thread: ERROR mq_close failed\n"); + } + + printf("sender_thread: returning nerrors=%d\n", nerrors); + return (pthread_addr_t)nerrors; +} + +static void *receiver_thread(void *arg) +{ + mqd_t mqfd; + char msg_buffer[TEST_MSGLEN]; + struct mq_attr attr; + int nbytes; + int nerrors = 0; + int i; + + printf("receiver_thread: Starting\n"); + + /* Fill in attributes for message queue */ + + attr.mq_maxmsg = 20; + attr.mq_msgsize = TEST_MSGLEN; + attr.mq_flags = 0; + + /* Set the flags for the open of the queue. + * Make it a blocking open on the queue, meaning it will block if + * this task tries to read from the queue when the queue is empty + * + * O_CREAT - the queue will get created if it does not already exist. + * O_RDONLY - we are only planning to read from the queue. + * + * Open the queue, and create it if the sending process hasn't + * already created it. + */ + + mqfd = mq_open("testmq", O_RDONLY|O_CREAT, 0666, &attr); + if (mqfd < 0) + { + printf("receiver_thread: ERROR mq_open failed\n"); + pthread_exit((pthread_addr_t)1); + } + + /* Perform the receive TEST_RECEIVE_NMSGS times */ + + for (i = 0; i < TEST_RECEIVE_NMSGS; i++) + { + memset(msg_buffer, 0xaa, TEST_MSGLEN); + nbytes = mq_receive(mqfd, msg_buffer, TEST_MSGLEN, 0); + if (nbytes < 0) + { + /* mq_receive failed. If the error is because of EINTR then + * it is not a failure. + */ + + if (errno != EINTR) + { + printf("receiver_thread: ERROR mq_receive failure on msg %d, errno=%d\n", i, errno); + nerrors++; + } + else + { + printf("receiver_thread: mq_receive interrupted!\n", i); + } + } + else if (nbytes != TEST_MSGLEN) + { + printf("receiver_thread: mq_receive return bad size %d on msg %d\n", nbytes, i); + nerrors++; + } + else if (memcmp(TEST_MESSAGE, msg_buffer, nbytes) != 0) + { + int j; + + printf("receiver_thread: mq_receive returned corrupt message on msg %d\n", i); + printf("receiver_thread: i Expected Received\n"); + + for (j = 0; j < TEST_MSGLEN-1; j++) + { + if (isprint(msg_buffer[j])) + { + printf("receiver_thread: %2d %02x (%c) %02x (%c)\n", + j, TEST_MESSAGE[j], TEST_MESSAGE[j], msg_buffer[j], msg_buffer[j]); + } + else + { + printf("receiver_thread: %2d %02x (%c) %02x\n", + j, TEST_MESSAGE[j], TEST_MESSAGE[j], msg_buffer[j]); + } + } + printf("receiver_thread: %2d 00 %02x\n", + j, msg_buffer[j]); + } + else + { + printf("receiver_thread: mq_receive succeeded on msg %d\n", i); + } + } + + /* Close the queue and return success */ + + if (mq_close(mqfd) < 0) + { + printf("receiver_thread: ERROR mq_close failed\n"); + nerrors++; + } + + /* Destroy the queue */ + + if (mq_unlink("testmq") < 0) + { + printf("receiver_thread: ERROR mq_close failed\n"); + nerrors++; + } + + printf("receiver_thread: returning nerrors=%d\n", nerrors); + pthread_exit((pthread_addr_t)nerrors); + return (pthread_addr_t)nerrors; +} + +void mqueue_test(void) +{ + pthread_t sender; + pthread_t receiver; + void *result; + pthread_attr_t attr; + struct sched_param sparam; + int prio_min; + int prio_max; + int prio_mid; + int status; + + /* Start the sending thread at higher priority */ + + printf("mqueue_test: Starting receiver\n"); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("mqueue_test: pthread_attr_init failed, status=%d\n", status); + } + + status = pthread_attr_setstacksize(&attr, STACKSIZE); + if (status != 0) + { + printf("mqueue_test: pthread_attr_setstacksize failed, status=%d\n", status); + } + + prio_min = sched_get_priority_min(SCHED_FIFO); + prio_max = sched_get_priority_max(SCHED_FIFO); + prio_mid = (prio_min + prio_max) / 2; + + sparam.sched_priority = prio_mid; + status = pthread_attr_setschedparam(&attr,&sparam); + if (status != OK) + { + printf("mqueue_test: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("mqueue_test: Set receiver priority to %d\n", sparam.sched_priority); + } + + status = pthread_create(&receiver, &attr, receiver_thread, NULL); + if (status != 0) + { + printf("mqueue_test: pthread_create failed, status=%d\n", status); + } + + /* Start the sending thread at lower priority */ + + printf("mqueue_test: Starting sender\n"); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("mqueue_test: pthread_attr_init failed, status=%d\n", status); + } + + status = pthread_attr_setstacksize(&attr, STACKSIZE); + if (status != 0) + { + printf("mqueue_test: pthread_attr_setstacksize failed, status=%d\n", status); + } + + sparam.sched_priority = (prio_min + prio_mid) / 2; + status = pthread_attr_setschedparam(&attr,&sparam); + if (status != OK) + { + printf("mqueue_test: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("mqueue_test: Set sender thread priority to %d\n", sparam.sched_priority); + } + + status = pthread_create(&sender, &attr, sender_thread, NULL); + if (status != 0) + { + printf("mqueue_test: pthread_create failed, status=%d\n", status); + } + + printf("mqueue_test: Waiting for sender to complete\n"); + pthread_join(sender, &result); + if (result != (void*)0) + { + printf("mqueue_test: ERROR sender thread exited with %d errors\n", (int)result); + } + +#ifndef CONFIG_DISABLE_SIGNALS + /* Wake up the receiver thread with a signal */ + + printf("mqueue_test: Killing receiver\n"); + pthread_kill(receiver, 9); + + /* Wait a bit to see if the thread exits on its own */ + + usleep(HALF_SECOND_USEC_USEC); +#endif + + /* Then cancel the thread and see if it did */ + + printf("mqueue_test: Canceling receiver\n"); + status = pthread_cancel(receiver); + if (status == ESRCH) + { + printf("mqueue_test: receiver has already terminated\n"); + } + + pthread_join(receiver, &result); + if (result != (void*)0) + { + printf("mqueue_test: ERROR receiver thread exited with %d errors\n", (int)result); + } +} + + diff --git a/apps/examples/ostest/mutex.c b/apps/examples/ostest/mutex.c new file mode 100644 index 000000000..752f833f2 --- /dev/null +++ b/apps/examples/ostest/mutex.c @@ -0,0 +1,142 @@ +/*********************************************************************** + * mutex.c + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ***********************************************************************/ + +#include <stdio.h> +#include <pthread.h> +#include "ostest.h" + +#ifndef NULL +# define NULL (void*)0 +#endif + +#define NLOOPS 32 + +static pthread_mutex_t mut; +static volatile int my_mutex = 0; +static unsigned long nloops[2] = {0, 0}; +static unsigned long nerrors[2] = {0, 0}; + +static void *thread_func(void *parameter) +{ + int id = (int)parameter; + int ndx = id - 1; + int i; + + for (nloops[ndx] = 0; nloops[ndx] < NLOOPS; nloops[ndx]++) + { + int status = pthread_mutex_lock(&mut); + if (status != 0) + { + printf("ERROR thread %d: pthread_mutex_lock failed, status=%d\n", + id, status); + } + + if (my_mutex == 1) + { + printf("ERROR thread=%d: " + "my_mutex should be zero, instead my_mutex=%d\n", + id, my_mutex); + nerrors[ndx]++; + } + + my_mutex = 1; + for (i = 0; i < 10; i++) + { + pthread_yield(); + } + my_mutex = 0; + + status = pthread_mutex_unlock(&mut); + if (status != 0) + { + printf("ERROR thread %d: pthread_mutex_unlock failed, status=%d\n", + id, status); + } + } + pthread_exit(NULL); + return NULL; /* Non-reachable -- needed for some compilers */ +} + +void mutex_test(void) +{ + pthread_t thread1, thread2; +#ifdef SDCC + pthread_addr_t result1, result2; + pthread_attr_t attr; +#endif + int status; + + /* Initialize the mutex */ + + printf("Initializing mutex\n"); + pthread_mutex_init(&mut, NULL); + + /* Start two thread instances */ + + printf("Starting thread 1\n"); +#ifdef SDCC + (void)pthread_attr_init(&attr); + status = pthread_create(&thread1, &attr, thread_func, (pthread_addr_t)1); +#else + status = pthread_create(&thread1, NULL, thread_func, (pthread_addr_t)1); +#endif + if (status != 0) + { + printf("Error in thread#1 creation\n"); + } + + printf("Starting thread 2\n"); +#ifdef SDCC + status = pthread_create(&thread2, &attr, thread_func, (pthread_addr_t)2); +#else + status = pthread_create(&thread2, NULL, thread_func, (pthread_addr_t)2); +#endif + if (status != 0) + { + printf("Error in thread#2 creation\n"); + } + +#ifdef SDCC + pthread_join(thread1, &result1); + pthread_join(thread2, &result2); +#else + pthread_join(thread1, NULL); + pthread_join(thread2, NULL); +#endif + + printf("\t\tThread1\tThread2\n"); + printf("\tLoops\t%ld\t%ld\n", nloops[0], nloops[1]); + printf("\tErrors\t%ld\t%ld\n", nerrors[0], nerrors[1]); +} diff --git a/apps/examples/ostest/ostest.h b/apps/examples/ostest/ostest.h new file mode 100644 index 000000000..99290828e --- /dev/null +++ b/apps/examples/ostest/ostest.h @@ -0,0 +1,174 @@ +/**************************************************************************** + * examples/ostest/ostest.h + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __OSTEST_H +#define __OSTEST_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* The task_create task size can be specified in the defconfig file */ + +#ifdef CONFIG_EXAMPLES_OSTEST_STACKSIZE +# define STACKSIZE CONFIG_EXAMPLES_OSTEST_STACKSIZE +#else +# define STACKSIZE 8192 +#endif + +/* The number of times to execute the test can be specified in the defconfig + * file. + */ + +#ifndef CONFIG_EXAMPLES_OSTEST_LOOPS +# define CONFIG_EXAMPLES_OSTEST_LOOPS 1 +#endif + +/* This is the number of threads that are created in the barrier test. + * A smaller number should be selected on systems without sufficient memory + * to start so many threads. + */ + +#ifndef CONFIG_EXAMPLES_OSTEST_NBARRIER_THREADS +# define CONFIG_EXAMPLES_OSTEST_NBARRIER_THREADS 8 +#endif + +/* Priority inheritance */ + +#if defined(CONFIG_DEBUG) && defined(CONFIG_PRIORITY_INHERITANCE) && defined(CONFIG_SEM_PHDEBUG) +# define dump_nfreeholders(s) printf(s " nfreeholders: %d\n", sem_nfreeholders()) +#else +# define dump_nfreeholders(s) +#endif + +/* If CONFIG_STDIO_LINEBUFFER is defined, the STDIO buffer will be flushed + * on each new line. Otherwise, STDIO needs to be explicitly flushed to + * see the output in context. + */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && \ + CONFIG_STDIO_BUFFER_SIZE > 0 && !defined(CONFIG_STDIO_LINEBUFFER) +# define FFLUSH() fflush(stdout) +#else +# define FFLUSH() +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* dev_null.c ***************************************************************/ + +extern int dev_null(void); + +/* mutex.c ******************************************************************/ + +extern void mutex_test(void); + +/* rmutex.c ******************************************************************/ + +extern void recursive_mutex_test(void); + +/* sem.c ********************************************************************/ + +extern void sem_test(void); + +/* cond.c *******************************************************************/ + +extern void cond_test(void); + +/* mqueue.c *****************************************************************/ + +extern void mqueue_test(void); + +/* timedmqueue.c ************************************************************/ + +extern void timedmqueue_test(void); + +/* cancel.c *****************************************************************/ + +extern void cancel_test(void); + +/* timedwait.c **************************************************************/ + +extern void timedwait_test(void); + +/* sighand.c ****************************************************************/ + +extern void sighand_test(void); + +/* posixtimers.c ************************************************************/ + +extern void timer_test(void); + +/* roundrobin.c *************************************************************/ + +extern void rr_test(void); + +/* barrier.c ****************************************************************/ + +extern void barrier_test(void); + +/* prioinherit.c ************************************************************/ + +extern void priority_inheritance(void); + +/* APIs exported (conditionally) by the OS specifically for testing of + * priority inheritance + */ + +#if defined(CONFIG_DEBUG) && defined(CONFIG_PRIORITY_INHERITANCE) && defined(CONFIG_SEM_PHDEBUG) +extern void sem_enumholders(FAR sem_t *sem); +extern int sem_nfreeholders(void); +#else +# define sem_enumholders(sem) +# define sem_nfreeholders() +#endif + +#endif /* __OSTEST_H */ diff --git a/apps/examples/ostest/posixtimer.c b/apps/examples/ostest/posixtimer.c new file mode 100644 index 000000000..3560c712b --- /dev/null +++ b/apps/examples/ostest/posixtimer.c @@ -0,0 +1,262 @@ +/*********************************************************************** + * examples/ostest/posixtimer.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ***********************************************************************/ + +/************************************************************************** + * Included Files + **************************************************************************/ + +#include <stdio.h> +#include <unistd.h> +#include <semaphore.h> +#include <signal.h> +#include <sched.h> +#include <errno.h> +#include "ostest.h" + +/************************************************************************** + * Private Definitions + **************************************************************************/ + +#ifndef NULL +# define NULL (void*)0 +#endif + +#define MY_TIMER_SIGNAL 17 +#define SIGVALUE_INT 42 + +/************************************************************************** + * Private Data + **************************************************************************/ + +static sem_t sem; +static int g_nsigreceived = 0; + +/************************************************************************** + * Private Functions + **************************************************************************/ + +static void timer_expiration(int signo, siginfo_t *info, void *ucontext) +{ + sigset_t oldset; + sigset_t allsigs; + int status; + + printf("timer_expiration: Received signal %d\n" , signo); + + g_nsigreceived++; + + /* Check signo */ + + if (signo != MY_TIMER_SIGNAL) + { + printf("timer_expiration: ERROR expected signo=%d\n" , MY_TIMER_SIGNAL); + } + + /* Check siginfo */ + + if (info->si_value.sival_int != SIGVALUE_INT) + { + printf("timer_expiration: ERROR sival_int=%d expected %d\n", + info->si_value.sival_int, SIGVALUE_INT); + } + else + { + printf("timer_expiration: sival_int=%d\n" , info->si_value.sival_int); + } + + if (info->si_signo != MY_TIMER_SIGNAL) + { + printf("timer_expiration: ERROR expected si_signo=%d, got=%d\n", + MY_TIMER_SIGNAL, info->si_signo); + } + + if (info->si_code == SI_TIMER) + { + printf("timer_expiration: si_code=%d (SI_TIMER)\n" , info->si_code); + } + else + { + printf("timer_expiration: ERROR si_code=%d, expected SI_TIMER=%d\n", + info->si_code, SI_TIMER); + } + + /* Check ucontext_t */ + + printf("timer_expiration: ucontext=%p\n" , ucontext); + + /* Check sigprocmask */ + + (void)sigfillset(&allsigs); + status = sigprocmask(SIG_SETMASK, NULL, &oldset); + if (status != OK) + { + printf("timer_expiration: ERROR sigprocmask failed, status=%d\n", + status); + } + + if (oldset != allsigs) + { + printf("timer_expiration: ERROR sigprocmask=%x expected=%x\n", + oldset, allsigs); + } + +} + +/************************************************************************** + * Public Functions + **************************************************************************/ + +void timer_test(void) +{ + sigset_t sigset; + struct sigaction act; + struct sigaction oact; + struct sigevent notify; + struct itimerspec timer; + timer_t timerid; + int status; + int i; + + printf("timer_test: Initializing semaphore to 0\n" ); + sem_init(&sem, 0, 0); + + /* Start waiter thread */ + + printf("timer_test: Unmasking signal %d\n" , MY_TIMER_SIGNAL); + + (void)sigemptyset(&sigset); + (void)sigaddset(&sigset, MY_TIMER_SIGNAL); + status = sigprocmask(SIG_UNBLOCK, &sigset, NULL); + if (status != OK) + { + printf("timer_test: ERROR sigprocmask failed, status=%d\n", + status); + } + + printf("timer_test: Registering signal handler\n" ); + act.sa_sigaction = timer_expiration; + act.sa_flags = SA_SIGINFO; + + (void)sigfillset(&act.sa_mask); + (void)sigdelset(&act.sa_mask, MY_TIMER_SIGNAL); + + status = sigaction(MY_TIMER_SIGNAL, &act, &oact); + if (status != OK) + { + printf("timer_test: ERROR sigaction failed, status=%d\n" , status); + } + +#ifndef SDCC + printf("timer_test: oact.sigaction=%p oact.sa_flags=%x oact.sa_mask=%x\n", + oact.sa_sigaction, oact.sa_flags, oact.sa_mask); +#endif + + /* Create the POSIX timer */ + + printf("timer_test: Creating timer\n" ); + + notify.sigev_notify = SIGEV_SIGNAL; + notify.sigev_signo = MY_TIMER_SIGNAL; + notify.sigev_value.sival_int = SIGVALUE_INT; + + status = timer_create(CLOCK_REALTIME, ¬ify, &timerid); + if (status != OK) + { + printf("timer_test: timer_create failed, errno=%d\n", errno); + goto errorout; + } + + /* Start the POSIX timer */ + + printf("timer_test: Starting timer\n" ); + + timer.it_value.tv_sec = 2; + timer.it_value.tv_nsec = 0; + timer.it_interval.tv_sec = 2; + timer.it_interval.tv_nsec = 0; + + status = timer_settime(timerid, 0, &timer, NULL); + if (status != OK) + { + printf("timer_test: timer_settime failed, errno=%d\n", errno); + goto errorout; + } + + /* Take the semaphore */ + + for (i = 0; i < 5; i++) + { + printf("timer_test: Waiting on semaphore\n" ); + FFLUSH(); + status = sem_wait(&sem); + if (status != 0) + { + int error = errno; + if (error == EINTR) + { + printf("timer_test: sem_wait() successfully interrupted by signal\n" ); + } + else + { + printf("timer_test: ERROR sem_wait failed, errno=%d\n" , error); + } + } + else + { + printf("timer_test: ERROR awakened with no error!\n" ); + } + printf("timer_test: g_nsigreceived=%d\n", g_nsigreceived); + } + +errorout: + sem_destroy(&sem); + + /* Then delete the timer */ + + printf("timer_test: Deleting timer\n" ); + status = timer_delete(timerid); + if (status != OK) + { + printf("timer_test: timer_create failed, errno=%d\n", errno); + } + + /* Detach the signal handler */ + + act.sa_sigaction = SIG_DFL; + status = sigaction(MY_TIMER_SIGNAL, &act, &oact); + + printf("timer_test: done\n" ); + FFLUSH(); +} diff --git a/apps/examples/ostest/prioinherit.c b/apps/examples/ostest/prioinherit.c new file mode 100644 index 000000000..993c9e14a --- /dev/null +++ b/apps/examples/ostest/prioinherit.c @@ -0,0 +1,541 @@ +/**************************************************************************** + * examples/ostest/prioinherit.c + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <unistd.h> +#include <semaphore.h> +#include <pthread.h> +#include <errno.h> + +#ifdef CONFIG_ARCH_SIM +# include <nuttx/arch.h> +#endif + +#include "ostest.h" + +#if defined(CONFIG_PRIORITY_INHERITANCE) && !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_PTHREAD) + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifndef CONFIG_SEM_PREALLOCHOLDERS +# define CONFIG_SEM_PREALLOCHOLDERS 0 +#endif +#define NLOWPRI_THREADS (CONFIG_SEM_PREALLOCHOLDERS+1) + +#ifndef CONFIG_SEM_NNESTPRIO +# define CONFIG_SEM_NNESTPRIO 0 +#endif +#define NHIGHPRI_THREADS (CONFIG_SEM_NNESTPRIO+1) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +enum thstate_e +{ + NOTSTARTED = 0, + RUNNING, + WAITING, + DONE +}; + +static sem_t g_sem; +static volatile enum thstate_e g_middlestate; +static volatile enum thstate_e g_highstate[NHIGHPRI_THREADS]; +static volatile enum thstate_e g_lowstate[NLOWPRI_THREADS]; +static int g_highpri; +static int g_medpri; +static int g_lowpri; + +/**************************************************************************** + * Name: nhighpri_waiting + ****************************************************************************/ + +static int nhighpri_waiting(void) +{ + int n = 0; + int i; + + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + if (g_highstate[i] == WAITING) + { + n++; + } + } + return n; +} + +/**************************************************************************** + * Name: nhighpri_running + ****************************************************************************/ + +static int nhighpri_running(void) +{ + int n = 0; + int i; + + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + if (g_highstate[i] != DONE) + { + n++; + } + } + return n; +} + +/**************************************************************************** + * Name: highpri_thread + ****************************************************************************/ + +static void *highpri_thread(void *parameter) +{ + int threadno = (int)parameter; + int ret; + + g_highstate[threadno-1] = RUNNING; + + printf("highpri_thread-%d: Started\n", threadno); + FFLUSH(); + sleep(1); + + printf("highpri_thread-%d: Calling sem_wait()\n", threadno); + g_highstate[threadno-1] = WAITING; + ret = sem_wait(&g_sem); + g_highstate[threadno-1] = DONE; + + if (ret != 0) + { + printf("highpri_thread-%d: sem_take failed: %d\n", threadno, ret); + } + else if (g_middlestate == RUNNING) + { + printf("highpri_thread-%d: SUCCESS midpri_thread is still running!\n", threadno); + } + else + { + printf("highpri_thread-%d: ERROR -- midpri_thread has already exited!\n", threadno); + } + + sem_post(&g_sem); + printf("highpri_thread-%d: Okay... I'm done!\n", threadno); + FFLUSH(); + return NULL; +} + +/**************************************************************************** + * Name: hog_cpu + ****************************************************************************/ + +static inline void hog_cpu(void) +{ +#ifdef CONFIG_ARCH_SIM + /* The simulator doesn't have any mechanism to do asynchronous pre-emption + * (basically because it doesn't have any interupts/asynchronous events). + * The simulator does "fake" a timer interrupt in up_idle() -- the idle + * thread that only executes when nothing else is running. In the simulator, + * we cannot suspend the middle priority task, or we wouldn't have the + * test that we want. So, we have no option but to pump the fake clock + * here by calling up_idle(). Sigh! + */ + + up_idle(); +#else + /* On real platforms with a real timer interrupt, we really can hog the + * CPU. When the sleep() goes off in priority_inheritance(), it will + * wake up and start the high priority thread. + */ + + volatile int i; + for (i = 0; i < INT_MAX; i++); +#endif +} + +/**************************************************************************** + * Name: medpri_thread + ****************************************************************************/ + +static void *medpri_thread(void *parameter) +{ + printf("medpri_thread: Started ... I won't let go of the CPU!\n"); + g_middlestate = RUNNING; + FFLUSH(); + + /* The following loop will completely block lowpri_thread from running. + * UNLESS priority inheritance is working. In that case, its priority + * will be boosted. + */ + + while (nhighpri_running() > 0) + { + hog_cpu(); + } + + printf("medpri_thread: Okay... I'm done!\n"); + FFLUSH(); + g_middlestate = DONE; + return NULL; +} + +/**************************************************************************** + * Name: lowpri_thread + ****************************************************************************/ + +static void *lowpri_thread(void *parameter) +{ + void *retval = (void*)-1; + struct sched_param sparam; + int threadno = (int)parameter; + int expected; + int count; + int policy; + int ret; + int nwaiting; + int i; + + g_lowstate[threadno-1] = RUNNING; + printf("lowpri_thread-%d: Started\n", threadno); + + ret = pthread_getschedparam(pthread_self(), &policy, &sparam); + if (ret != 0) + { + printf("lowpri_thread-%d: ERROR pthread_getschedparam failed: %d\n", threadno, ret); + } + else + { + printf("lowpri_thread-%d: initial priority: %d\n", threadno, sparam.sched_priority); + if (sparam.sched_priority != g_lowpri) + { + printf(" ERROR should have been %d\n", g_lowpri); + } + } + + g_lowstate[threadno-1] = WAITING; + ret = sem_wait(&g_sem); + if (ret != 0) + { + printf("lowpri_thread-%d: sem_take failed: %d\n", threadno, ret); + } + else + { + /* Hang on to the thread until the middle priority thread runs */ + + while (g_middlestate == NOTSTARTED && nhighpri_waiting() < NHIGHPRI_THREADS) + { + printf("lowpri_thread-%d: Waiting for the midle pri task to run\n", threadno); + printf(" g_middlestate: %d\n", (int)g_middlestate); + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + printf(" g_highstate[%d]: %d\n", i, (int)g_highstate[i]); + } + printf(" I still have a count on the semaphore\n"); + sem_enumholders(&g_sem); + FFLUSH(); + sleep(1); + } + + /* Account for all of the semaphore counts. At any given time if there are 'n' + * running hight prioity tasks, then the semaphore count should be '-n' + */ + + sched_lock(); /* Needs to be atomic */ + ret = sem_getvalue(&g_sem, &count); + nwaiting = nhighpri_waiting(); + sched_unlock(); + + if (ret < 0) + { + printf("lowpri_thread-%d: ERROR sem_getvalue failed: %d\n", threadno, errno); + } + printf("lowpri_thread-%d: Sem count: %d, No. highpri thread: %d\n", threadno, count, nwaiting); + + /* The middle priority task is running, let go of the semaphore */ + + if (g_middlestate == RUNNING && nwaiting == -count) + { + /* Good.. the middle priority task is still running and the counts are okay. */ + + retval = NULL; + } + else + { + /* If the sem count is positive, then there all of the higher priority threads + * should have already completed. + */ + + printf("lowpri_thread-%d: %s the middle priority task has already exitted!\n", + threadno, count >= 0 ? "SUCCESS" : "ERROR" ); + printf(" g_middlestate: %d sem count=%d\n", (int)g_middlestate, count); + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + printf(" g_highstate[%d]: %d\n", i, (int)g_highstate[i]); + } + } + } + + ret = pthread_getschedparam(pthread_self(), &policy, &sparam); + sem_enumholders(&g_sem); + sem_post(&g_sem); + if (ret != 0) + { + printf("lowpri_thread-%d: ERROR pthread_getschedparam failed: %d\n", threadno, ret); + } + else + { + if (nwaiting > 0) + { + expected = g_highpri; + } + else + { + expected = g_lowpri; + } + + printf("lowpri_thread-%d: %s priority before sem_post: %d\n", + threadno, + sparam.sched_priority != expected ? "ERROR" : "SUCCESS", + sparam.sched_priority); + + if (sparam.sched_priority != expected) + { + printf(" ERROR should have been %d\n", expected); + } + } + + ret = pthread_getschedparam(pthread_self(), &policy, &sparam); + if (ret != 0) + { + printf("lowpri_thread-%d: ERROR pthread_getschedparam failed: %d\n", threadno, ret); + } + else + { + printf("lowpri_thread-%d: %s final priority: %d\n", + threadno, + sparam.sched_priority != g_lowpri ? "ERROR" : "SUCCESS", + sparam.sched_priority); + + if (sparam.sched_priority != g_lowpri) + { + printf(" ERROR should have been %d\n", g_lowpri); + } + } + sem_enumholders(&g_sem); + + printf("lowpri_thread-%d: Okay... I'm done!\n", threadno); + FFLUSH(); + g_lowstate[threadno-1] = DONE; + return retval; +} +#endif /* CONFIG_PRIORITY_INHERITANCE && !CONFIG_DISABLE_SIGNALS && !CONFIG_DISABLE_PTHREAD */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: priority_inheritance + ****************************************************************************/ + +void priority_inheritance(void) +{ +#if defined(CONFIG_PRIORITY_INHERITANCE) && !defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_PTHREAD) + pthread_t lowpri[NLOWPRI_THREADS]; + pthread_t medpri; + pthread_t highpri[NHIGHPRI_THREADS]; + pthread_addr_t result; + pthread_attr_t attr; + struct sched_param sparam; + int my_pri; + int status; + int i; + + printf("priority_inheritance: Started\n"); + + g_middlestate = NOTSTARTED; + for (i = 0; i < NHIGHPRI_THREADS; i++) g_highstate[i] = NOTSTARTED; + for (i = 0; i < NLOWPRI_THREADS; i++) g_lowstate[i] = NOTSTARTED; + + status = sched_getparam (getpid(), &sparam); + if (status != 0) + { + printf("priority_inheritance: sched_getparam failed\n"); + sparam.sched_priority = PTHREAD_DEFAULT_PRIORITY; + } + my_pri = sparam.sched_priority; + + g_highpri = sched_get_priority_max(SCHED_FIFO); + g_lowpri = sched_get_priority_min(SCHED_FIFO); + g_medpri = my_pri - 1; + + sem_init(&g_sem, 0, NLOWPRI_THREADS); + dump_nfreeholders("priority_inheritance:"); + + /* Start the low priority threads */ + + for (i = 0; i < NLOWPRI_THREADS; i++) + { + int threadno = i+1; + printf("priority_inheritance: Starting lowpri_thread-%d (of %d) at %d\n", + threadno, NLOWPRI_THREADS, g_lowpri); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("priority_inheritance: pthread_attr_init failed, status=%d\n", status); + } + sparam.sched_priority = g_lowpri; + status = pthread_attr_setschedparam(&attr,& sparam); + if (status != OK) + { + printf("priority_inheritance: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("priority_inheritance: Set lowpri_thread-%d priority to %d\n", + threadno, sparam.sched_priority); + } + + status = pthread_create(&lowpri[i], &attr, lowpri_thread, (void*)threadno); + if (status != 0) + { + printf("priority_inheritance: pthread_create failed, status=%d\n", status); + } + } + printf("priority_inheritance: Waiting...\n"); + sleep(2); + dump_nfreeholders("priority_inheritance:"); + + /* Start the medium priority thread */ + + printf("priority_inheritance: Starting medpri_thread at %d\n", g_medpri); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("priority_inheritance: pthread_attr_init failed, status=%d\n", status); + } + + sparam.sched_priority = g_medpri; + status = pthread_attr_setschedparam(&attr,& sparam); + if (status != OK) + { + printf("priority_inheritance: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("priority_inheritance: Set medpri_thread priority to %d\n", sparam.sched_priority); + } + FFLUSH(); + + status = pthread_create(&medpri, &attr, medpri_thread, NULL); + if (status != 0) + { + printf("priority_inheritance: pthread_create failed, status=%d\n", status); + } + printf("priority_inheritance: Waiting...\n"); + sleep(1); + dump_nfreeholders("priority_inheritance:"); + + /* Start the high priority threads */ + + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + int threadno = i+1; + printf("priority_inheritance: Starting highpri_thread-%d (of %d) at %d\n", + threadno, NHIGHPRI_THREADS, g_highpri); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("priority_inheritance: pthread_attr_init failed, status=%d\n", status); + } + + sparam.sched_priority = g_highpri - i; + status = pthread_attr_setschedparam(&attr,& sparam); + if (status != OK) + { + printf("priority_inheritance: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("priority_inheritance: Set highpri_thread-%d priority to %d\n", + threadno, sparam.sched_priority); + } + FFLUSH(); + + status = pthread_create(&highpri[i], &attr, highpri_thread, (void*)threadno); + if (status != 0) + { + printf("priority_inheritance: pthread_create failed, status=%d\n", status); + } + } + dump_nfreeholders("priority_inheritance:"); + FFLUSH(); + + /* Wait for all thread instances to complete */ + + for (i = 0; i < NHIGHPRI_THREADS; i++) + { + printf("priority_inheritance: Waiting for highpri_thread-%d to complete\n", i+1); + FFLUSH(); + (void)pthread_join(highpri[i], &result); + dump_nfreeholders("priority_inheritance:"); + } + printf("priority_inheritance: Waiting for medpri_thread to complete\n"); + FFLUSH(); + (void)pthread_join(medpri, &result); + dump_nfreeholders("priority_inheritance:"); + for (i = 0; i < NLOWPRI_THREADS; i++) + { + printf("priority_inheritance: Waiting for lowpri_thread-%d to complete\n", i+1); + FFLUSH(); + (void)pthread_join(lowpri[i], &result); + dump_nfreeholders("priority_inheritance:"); + } + + printf("priority_inheritance: Finished\n"); + sem_destroy(&g_sem); + dump_nfreeholders("priority_inheritance:"); + FFLUSH(); +#endif /* CONFIG_PRIORITY_INHERITANCE && !CONFIG_DISABLE_SIGNALS && !CONFIG_DISABLE_PTHREAD */ +} diff --git a/apps/examples/ostest/rmutex.c b/apps/examples/ostest/rmutex.c new file mode 100644 index 000000000..44eb4bb3b --- /dev/null +++ b/apps/examples/ostest/rmutex.c @@ -0,0 +1,166 @@ +/*********************************************************************** + * rmutex.c + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ***********************************************************************/ + +#include <stdio.h> +#include <pthread.h> +#include "ostest.h" + +#ifndef NULL +# define NULL (void*)0 +#endif + +#define NTHREADS 3 +#define NLOOPS 3 +#define NRECURSIONS 3 + +static pthread_mutex_t mut; + +static void thread_inner(int id, int level) +{ + int status; + if (level < NRECURSIONS) + { + /* Take the mutex */ + + printf("thread_inner[%d, %d]: Locking\n", id, level); + status = pthread_mutex_lock(&mut); + if (status != 0) + { + printf("thread_inner[%d, %d]: ERROR pthread_mutex_lock failed: %d\n", + id, level, status); + } + printf("thread_inner[%d, %d]: Locked\n", id, level); + + /* Give the other threads a chance */ + + pthread_yield(); + thread_inner(id, level+1); + pthread_yield(); + + /* Unlock the mutex */ + + printf("thread_inner[%d, %d]: Unlocking\n", id, level); + status = pthread_mutex_unlock(&mut); + if (status != 0) + { + printf("thread_inner[%d, %d]: ERROR pthread_mutex_unlock failed: %d\n", + id, level, status); + } + printf("thread_inner[%d, %d]: Unlocked\n", id, level); + pthread_yield(); + } +} + +static void *thread_outer(void *parameter) +{ + int i; + printf("thread_outer[%d]: Started\n", (int)parameter); + for (i = 0; i < NLOOPS; i++) + { + printf("thread_outer[%d]: Loop %d\n", (int)parameter, i); + thread_inner((int)parameter, 0); + } + printf("thread_outer[%d]: Exitting\n", (int)parameter); + pthread_exit(NULL); + return NULL; /* Non-reachable -- needed for some compilers */ +} + +void recursive_mutex_test(void) +{ + pthread_t thread[NTHREADS]; +#ifdef SDCC + pthread_addr_t result[NTHREADS]; + pthread_attr_t attr; +#endif + pthread_mutexattr_t mattr; + int type; + int status; + int i; + + /* Initialize the mutex attributes */ + + pthread_mutexattr_init(&mattr); + status = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); + if (status != 0) + { + printf("recursive_mutex_test: ERROR pthread_mutexattr_settype failed, status=%d\n", status); + } + + status = pthread_mutexattr_gettype(&mattr, &type); + if (status != 0) + { + printf("recursive_mutex_test: ERROR pthread_mutexattr_gettype failed, status=%d\n", status); + } + if (type != PTHREAD_MUTEX_RECURSIVE) + { + printf("recursive_mutex_test: ERROR pthread_mutexattr_gettype return type=%d\n", type); + } + + /* Initialize the mutex */ + + printf("recursive_mutex_test: Initializing mutex\n"); + pthread_mutex_init(&mut, &mattr); + + /* Start the threads -- all at the same, default priority */ + + for (i = 0; i < NTHREADS; i++) + { + printf("recursive_mutex_test: Starting thread %d\n", i+1); +#ifdef SDCC + (void)pthread_attr_init(&attr); + status = pthread_create(&thread[i], &attr, thread_outer, (pthread_addr_t)i+1); +#else + status = pthread_create(&thread[i], NULL, thread_outer, (pthread_addr_t)i+1); +#endif + if (status != 0) + { + printf("recursive_mutex_test: ERRROR thread#%d creation: %d\n", i+1, status); + } + } + + /* Wait for all; of the threads to complete */ + + for (i = 0; i < NTHREADS; i++) + { + printf("recursive_mutex_test: Waiting for thread %d\n", i+1); +#ifdef SDCC + pthread_join(thread[i], &result1); +#else + pthread_join(thread[i], NULL); +#endif + } + + printf("recursive_mutex_test: Complete\n"); +} diff --git a/apps/examples/ostest/roundrobin.c b/apps/examples/ostest/roundrobin.c new file mode 100644 index 000000000..061d51f3d --- /dev/null +++ b/apps/examples/ostest/roundrobin.c @@ -0,0 +1,232 @@ +/******************************************************************************** + * examples/ostest/roundrobin.c + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ********************************************************************************/ + +/******************************************************************************** + * Included Files + ********************************************************************************/ + +#include <nuttx/config.h> +#include <stdio.h> +#include "ostest.h" + +#if CONFIG_RR_INTERVAL > 0 + +/******************************************************************************** + * Definitions + ********************************************************************************/ + +/* This number may need to be tuned for different processor speeds. Since these + * arrays must be large to very correct SCHED_RR behavior, this test may require + * too much memory on many targets. + */ + +/* #define CONFIG_NINTEGERS 32768 Takes forever on 60Mhz ARM7 */ + +#define CONFIG_NINTEGERS 2048 + +/******************************************************************************** + * Private Data + ********************************************************************************/ + +static int prime1[CONFIG_NINTEGERS]; +static int prime2[CONFIG_NINTEGERS]; + +/******************************************************************************** + * Private Functions + ********************************************************************************/ + +/******************************************************************************** + * Name: dosieve + * + * Description + * This implements a "sieve of aristophanes" algorithm for finding prime number. + * Credit for this belongs to someone, but I am not sure who anymore. Anyway, + * the only purpose here is that we need some algorithm that takes a long period + * of time to execute. + * + ********************************************************************************/ + +static void dosieve(int *prime) +{ + int a,d; + int i; + int j; + + a = 2; + d = a; + + for (i = 0; i < CONFIG_NINTEGERS; i++) + { + prime[i] = i+2; + } + + for (i = 1; i < 10; i++) + { + for (j = 0; j < CONFIG_NINTEGERS; j++) + { + d = a + d; + if (d < CONFIG_NINTEGERS) + { + prime[d]=0; + } + } + a++; + d = a; + i++; + } + +#if 0 /* We don't really care what the numbers are */ + for (i = 0, j= 0; i < CONFIG_NINTEGERS; i++) + { + if (prime[i] != 0) + { + printf(" Prime %d: %d\n", j, prime[i]); + j++; + } + } +#endif +} + +/******************************************************************************** + * Name: sieve1 + ********************************************************************************/ + +static void *sieve1(void *parameter) +{ + int i; + + printf("sieve1 started\n"); + + for (i = 0; i < 1000; i++) + { + dosieve(prime1); + } + + printf("sieve1 finished\n"); + + pthread_exit(NULL); + return NULL; /* To keep some compilers happy */ +} + +/******************************************************************************** + * Name: sieve2 + ********************************************************************************/ + +static void *sieve2(void *parameter) +{ + int i; + + printf("sieve2 started\n"); + + for (i = 0; i < 1000; i++) + { + dosieve(prime2); + } + + printf("sieve2 finished\n"); + + pthread_exit(NULL); + return NULL; /* To keep some compilers happy */ +} + +/******************************************************************************** + * Public Functions + ********************************************************************************/ + +/******************************************************************************** + * Name: rr_test + ********************************************************************************/ + +void rr_test(void) +{ + pthread_t sieve1_thread; + pthread_t sieve2_thread; + struct sched_param sparam; + pthread_attr_t attr; + pthread_addr_t result; + int status; + + printf("rr_test: Starting sieve1 thread \n"); + status = pthread_attr_init(&attr); + if (status != OK) + { + printf("rr_test: pthread_attr_init failed, status=%d\n", status); + } + + sparam.sched_priority = sched_get_priority_min(SCHED_FIFO); + status = pthread_attr_setschedparam(&attr, &sparam); + if (status != OK) + { + printf("rr_test: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("rr_test: Set thread priority to %d\n", sparam.sched_priority); + } + + status = pthread_attr_setschedpolicy(&attr, SCHED_RR); + if (status != OK) + { + printf("rr_test: pthread_attr_setschedpolicy failed, status=%d\n", status); + } + else + { + printf("rr_test: Set thread policty to SCHED_RR\n"); + } + + status = pthread_create(&sieve1_thread, &attr, sieve1, NULL); + if (status != 0) + { + printf("rr_test: Error in thread 1 creation, status=%d\n", status); + } + + printf("rr_test: Starting sieve1 thread \n"); + + status = pthread_create(&sieve2_thread, &attr, sieve2, NULL); + if (status != 0) + { + printf("rr_test: Error in thread 2 creation, status=%d\n", status); + } + + printf("rr_test: Waiting for sieves to complete -- this should take awhile\n"); + printf("rr_test: If RR scheduling is working, they should start and complete at\n"); + printf("rr_test: about the same time\n"); + + pthread_join(sieve2_thread, &result); + pthread_join(sieve1_thread, &result); + printf("rr_test: Done\n"); +} + +#endif /* CONFIG_RR_INTERVAL */ diff --git a/apps/examples/ostest/sem.c b/apps/examples/ostest/sem.c new file mode 100644 index 000000000..850cf8040 --- /dev/null +++ b/apps/examples/ostest/sem.c @@ -0,0 +1,246 @@ +/*********************************************************************** + * sem.c + * + * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ***********************************************************************/ + +#include <stdio.h> +#include <pthread.h> +#include <semaphore.h> +#include <sched.h> +#include "ostest.h" + +#ifndef NULL +# define NULL (void*)0 +#endif + +static sem_t sem; + +static void *waiter_func(void *parameter) +{ + int id = (int)parameter; + int status; + int value; + + printf("waiter_func: Thread %d Started\n", id); + + /* Take the semaphore */ + + status = sem_getvalue(&sem, &value); + if (status < 0) + { + printf("waiter_func: ERROR thread %d could not get semaphore value\n", id); + } + else + { + printf("waiter_func: Thread %d initial semaphore value = %d\n", id, value); + } + + printf("waiter_func: Thread %d waiting on semaphore\n", id); + status = sem_wait(&sem); + if (status != 0) + { + printf("waiter_func: ERROR thread %d sem_wait failed\n", id); + } + printf("waiter_func: Thread %d awakened\n", id); + + status = sem_getvalue(&sem, &value); + if (status < 0) + { + printf("waiter_func: ERROR thread %d could not get semaphore value\n", id); + } + else + { + printf("waiter_func: Thread %d new semaphore value = %d\n", id, value); + } + + printf("waiter_func: Thread %d done\n", id); + return NULL; +} + +static void *poster_func(void *parameter) +{ + int id = (int)parameter; + int status; + int value; + + printf("poster_func: Thread %d started\n", id); + + /* Take the semaphore */ + + do + { + status = sem_getvalue(&sem, &value); + if (status < 0) + { + printf("poster_func: ERROR thread %d could not get semaphore value\n", id); + } + else + { + printf("poster_func: Thread %d semaphore value = %d\n", id, value); + } + + if (value < 0) + { + printf("poster_func: Thread %d posting semaphore\n", id); + status = sem_post(&sem); + if (status != 0) + { + printf("poster_func: ERROR thread %d sem_wait failed\n", id); + } + + pthread_yield(); + + status = sem_getvalue(&sem, &value); + if (status < 0) + { + printf("poster_func: ERROR thread %d could not get semaphore value\n", id); + } + else + { + printf("poster_func: Thread %d new semaphore value = %d\n", id, value); + } + } + } + while (value < 0); + + printf("poster_func: Thread %d done\n", id); + return NULL; + +} + +void sem_test(void) +{ + pthread_t waiter_thread1; + pthread_t waiter_thread2; + pthread_t poster_thread; +#ifdef SDCC + pthread_addr_t result; +#endif + struct sched_param sparam; + int prio_min; + int prio_max; + int prio_mid; + pthread_attr_t attr; + int status; + + printf("sem_test: Initializing semaphore to 0\n"); + sem_init(&sem, 0, 0); + + /* Start two waiter thread instances */ + + printf("sem_test: Starting waiter thread 1\n"); + status = pthread_attr_init(&attr); + if (status != OK) + { + printf("sem_test: pthread_attr_init failed, status=%d\n", status); + } + + prio_min = sched_get_priority_min(SCHED_FIFO); + prio_max = sched_get_priority_max(SCHED_FIFO); + prio_mid = (prio_min + prio_max) / 2; + + sparam.sched_priority = (prio_mid + prio_max) / 2; + status = pthread_attr_setschedparam(&attr,&sparam); + if (status != OK) + { + printf("sem_test: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("sem_test: Set thread 1 priority to %d\n", sparam.sched_priority); + } + + status = pthread_create(&waiter_thread1, &attr, waiter_func, (pthread_addr_t)1); + if (status != 0) + { + printf("sem_test: Error in thread 1 creation, status=%d\n", status); + } + + printf("sem_test: Starting waiter thread 2\n"); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("sem_test: pthread_attr_init failed, status=%d\n", status); + } + + sparam.sched_priority = prio_mid; + status = pthread_attr_setschedparam(&attr,&sparam); + if (status != OK) + { + printf("sem_test: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("sem_test: Set thread 2 priority to %d\n", sparam.sched_priority); + } + + status = pthread_create(&waiter_thread2, &attr, waiter_func, (pthread_addr_t)2); + if (status != 0) + { + printf("sem_test: Error in thread 2 creation, status=%d\n", status); + } + + printf("sem_test: Starting poster thread 3\n"); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("sem_test: pthread_attr_init failed, status=%d\n", status); + } + + sparam.sched_priority = (prio_min + prio_mid) / 2; + status = pthread_attr_setschedparam(&attr,&sparam); + if (status != OK) + { + printf("sem_test: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("sem_test: Set thread 3 priority to %d\n", sparam.sched_priority); + } + + status = pthread_create(&poster_thread, &attr, poster_func, (pthread_addr_t)3); + if (status != 0) + { + printf("sem_test: Error in thread 3 creation, status=%d\n", status); + } + +#ifdef SDCC + pthread_join(waiter_thread1, &result); + pthread_join(waiter_thread2, &result); + pthread_join(poster_thread, &result); +#else + pthread_join(waiter_thread1, NULL); + pthread_join(waiter_thread2, NULL); + pthread_join(poster_thread, NULL); +#endif +} diff --git a/apps/examples/ostest/sighand.c b/apps/examples/ostest/sighand.c new file mode 100644 index 000000000..681531639 --- /dev/null +++ b/apps/examples/ostest/sighand.c @@ -0,0 +1,267 @@ +/*********************************************************************** + * apps/examples/ostest/sighand.c + * + * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ***********************************************************************/ + +#include <sys/types.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <semaphore.h> +#include <signal.h> +#include <sched.h> +#include <errno.h> +#include "ostest.h" + +#ifndef NULL +# define NULL (void*)0 +#endif + +#define WAKEUP_SIGNAL 17 +#define SIGVALUE_INT 42 + +static sem_t sem; +static bool sigreceived = false; +static bool threadexited = false; + +static void wakeup_action(int signo, siginfo_t *info, void *ucontext) +{ + sigset_t oldset; + sigset_t allsigs; + int status; + + printf("wakeup_action: Received signal %d\n" , signo); + + sigreceived = true; + + /* Check signo */ + + if (signo != WAKEUP_SIGNAL) + { + printf("wakeup_action: ERROR expected signo=%d\n" , WAKEUP_SIGNAL); + } + + /* Check siginfo */ + + if (info->si_value.sival_int != SIGVALUE_INT) + { + printf("wakeup_action: ERROR sival_int=%d expected %d\n", + info->si_value.sival_int, SIGVALUE_INT); + } + else + { + printf("wakeup_action: sival_int=%d\n" , info->si_value.sival_int); + } + + if (info->si_signo != WAKEUP_SIGNAL) + { + printf("wakeup_action: ERROR expected si_signo=%d, got=%d\n", + WAKEUP_SIGNAL, info->si_signo); + } + + printf("wakeup_action: si_code=%d\n" , info->si_code); + + /* Check ucontext_t */ + + printf("wakeup_action: ucontext=%p\n" , ucontext); + + /* Check sigprocmask */ + + (void)sigfillset(&allsigs); + status = sigprocmask(SIG_SETMASK, NULL, &oldset); + if (status != OK) + { + printf("wakeup_action: ERROR sigprocmask failed, status=%d\n", + status); + } + + if (oldset != allsigs) + { + printf("wakeup_action: ERROR sigprocmask=%x expected=%x\n", + oldset, allsigs); + } +} + +static int waiter_main(int argc, char *argv[]) +{ + sigset_t sigset; + struct sigaction act; + struct sigaction oact; + int status; + + printf("waiter_main: Waiter started\n" ); + + printf("waiter_main: Unmasking signal %d\n" , WAKEUP_SIGNAL); + (void)sigemptyset(&sigset); + (void)sigaddset(&sigset, WAKEUP_SIGNAL); + status = sigprocmask(SIG_UNBLOCK, &sigset, NULL); + if (status != OK) + { + printf("waiter_main: ERROR sigprocmask failed, status=%d\n", + status); + } + + printf("waiter_main: Registering signal handler\n" ); + act.sa_sigaction = wakeup_action; + act.sa_flags = SA_SIGINFO; + + (void)sigfillset(&act.sa_mask); + (void)sigdelset(&act.sa_mask, WAKEUP_SIGNAL); + + status = sigaction(WAKEUP_SIGNAL, &act, &oact); + if (status != OK) + { + printf("waiter_main: ERROR sigaction failed, status=%d\n" , status); + } + +#ifndef SDCC + printf("waiter_main: oact.sigaction=%p oact.sa_flags=%x oact.sa_mask=%x\n", + oact.sa_sigaction, oact.sa_flags, oact.sa_mask); +#endif + + /* Take the semaphore */ + + printf("waiter_main: Waiting on semaphore\n" ); + FFLUSH(); + + status = sem_wait(&sem); + if (status != 0) + { + int error = errno; + if (error == EINTR) + { + printf("waiter_main: sem_wait() successfully interrupted by signal\n" ); + } + else + { + printf("waiter_main: ERROR sem_wait failed, errno=%d\n" , error); + } + } + else + { + printf("waiter_main: ERROR awakened with no error!\n" ); + } + + /* Detach the signal handler */ + + act.sa_sigaction = SIG_DFL; + status = sigaction(WAKEUP_SIGNAL, &act, &oact); + + printf("waiter_main: done\n" ); + FFLUSH(); + + threadexited = true; + return 0; +} + +void sighand_test(void) +{ + struct sched_param param; + union sigval sigvalue; + pid_t waiterpid; + int policy; + int status; + + printf("sighand_test: Initializing semaphore to 0\n" ); + sem_init(&sem, 0, 0); + + /* Start waiter thread */ + + printf("sighand_test: Starting waiter task\n" ); + status = sched_getparam (0, ¶m); + if (status != OK) + { + printf("sighand_test: ERROR sched_getparam() failed\n" ); + param.sched_priority = PTHREAD_DEFAULT_PRIORITY; + } + + policy = sched_getscheduler(0); + if (policy == ERROR) + { + printf("sighand_test: ERROR sched_getscheduler() failed\n" ); + policy = SCHED_FIFO; + } + + waiterpid = task_create("waiter", param.sched_priority, + PTHREAD_STACK_DEFAULT, waiter_main, NULL); + if (waiterpid == ERROR) + { + printf("sighand_test: ERROR failed to start waiter_main\n" ); + } + else + { + printf("sighand_test: Started waiter_main pid=%d\n", waiterpid); + } + + /* Wait a bit */ + + FFLUSH(); + sleep(2); + + /* Then signal the waiter thread. */ + + printf("sighand_test: Signaling pid=%d with signo=%d sigvalue=%d\n", + waiterpid, WAKEUP_SIGNAL, SIGVALUE_INT); + + sigvalue.sival_int = SIGVALUE_INT; +#ifdef CONFIG_CAN_PASS_STRUCTS + status = sigqueue(waiterpid, WAKEUP_SIGNAL, sigvalue); +#else + status = sigqueue(waiterpid, WAKEUP_SIGNAL, sigvalue.sival_ptr); +#endif + if (status != OK) + { + printf("sighand_test: ERROR sigqueue failed\n" ); + task_delete(waiterpid); + } + + /* Wait a bit */ + + FFLUSH(); + sleep(2); + + /* Then check the result */ + + if (!threadexited) + { + printf("sighand_test: ERROR waiter task did not exit\n" ); + } + + if (!sigreceived) + { + printf("sighand_test: ERROR signal handler did not run\n" ); + } + + printf("sighand_test: done\n" ); + FFLUSH(); +} diff --git a/apps/examples/ostest/timedmqueue.c b/apps/examples/ostest/timedmqueue.c new file mode 100644 index 000000000..807d8537b --- /dev/null +++ b/apps/examples/ostest/timedmqueue.c @@ -0,0 +1,387 @@ +/************************************************************************** + * apps/examples/ostest/mqueue.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/************************************************************************** + * Included Files + **************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <pthread.h> +#include <mqueue.h> +#include <sched.h> +#include <errno.h> + +#include "ostest.h" + +/************************************************************************** + * Private Definitions + **************************************************************************/ + +#define TEST_MESSAGE "This is a test and only a test" +#if defined(SDCC) || defined(__ZILOG__) + /* Cannot use strlen in array size */ + +# define TEST_MSGLEN (31) +#else + /* Message lenght is the size of the message plus the null terminator */ + +# define TEST_MSGLEN (strlen(TEST_MESSAGE)+1) +#endif + +#define TEST_SEND_NMSGS (10) +#define TEST_RECEIVE_NMSGS (10) + +/************************************************************************** + * Private Types + **************************************************************************/ + +/************************************************************************** + * Private Function Prototypes + **************************************************************************/ + +/************************************************************************** + * Global Variables + **************************************************************************/ + +/************************************************************************** + * Private Variables + **************************************************************************/ + +/************************************************************************** + * Private Functions + **************************************************************************/ + +/************************************************************************** + * Public Functions + **************************************************************************/ + +static void *sender_thread(void *arg) +{ + mqd_t mqfd; + char msg_buffer[TEST_MSGLEN]; + struct mq_attr attr; + int status = 0; + int nerrors = 0; + int i; + + printf("sender_thread: Starting\n"); + + /* Fill in attributes for message queue */ + + attr.mq_maxmsg = TEST_SEND_NMSGS-1; + attr.mq_msgsize = TEST_MSGLEN; + attr.mq_flags = 0; + + /* Set the flags for the open of the queue. + * Make it a blocking open on the queue, meaning it will block if + * this process tries to send to the queue and the queue is full. + * + * O_CREAT - the queue will get created if it does not already exist. + * O_WRONLY - we are only planning to write to the queue. + * + * Open the queue, and create it if the receiving process hasn't + * already created it. + */ + + mqfd = mq_open("testmq", O_WRONLY|O_CREAT, 0666, &attr); + if (mqfd < 0) + { + printf("sender_thread: ERROR mq_open failed\n"); + pthread_exit((pthread_addr_t)1); + } + + /* Fill in a test message buffer to send */ + + memcpy(msg_buffer, TEST_MESSAGE, TEST_MSGLEN); + + /* Perform the send TEST_SEND_NMSGS times */ + + for (i = 0; i < TEST_SEND_NMSGS; i++) + { + struct timespec ts; + status = clock_gettime(CLOCK_REALTIME, &ts); + if (status != 0) + { + printf("sender_thread: ERROR clock_gettime failed\n"); + } + ts.tv_sec += 5; + + /* The first TEST_SEND_NMSGS-1 send should succeed. The last + * one should fail with errno == ETIMEDOUT + */ + + status = mq_timedsend(mqfd, msg_buffer, TEST_MSGLEN, 42, &ts); + if (status < 0) + { + if (i == TEST_SEND_NMSGS-1 && errno == ETIMEDOUT) + { + printf("sender_thread: mq_timedsend %d timed out as expected\n", i); + } + else + { + printf("sender_thread: ERROR mq_timedsend failure=%d on msg %d\n", errno, i); + nerrors++; + } + } + else + { + if (i == TEST_SEND_NMSGS-1) + { + printf("sender_thread: ERROR mq_timedsend of msg %d succeeded\n", i); + nerrors++; + } + else + { + printf("sender_thread: mq_timedsend succeeded on msg %d\n", i); + } + } + } + + /* Close the queue and return success */ + + if (mq_close(mqfd) < 0) + { + printf("sender_thread: ERROR mq_close failed\n"); + } + + printf("sender_thread: returning nerrors=%d\n", nerrors); + FFLUSH(); + return (pthread_addr_t)nerrors; +} + +static void *receiver_thread(void *arg) +{ + mqd_t mqfd; + char msg_buffer[TEST_MSGLEN]; + struct mq_attr attr; + int nbytes; + int nerrors = 0; + int i; + + printf("receiver_thread: Starting\n"); + + /* Fill in attributes for message queue */ + + attr.mq_maxmsg = TEST_SEND_NMSGS-1; + attr.mq_msgsize = TEST_MSGLEN; + attr.mq_flags = 0; + + /* Set the flags for the open of the queue. + * Make it a blocking open on the queue, meaning it will block if + * this process tries to* send to the queue and the queue is full. + * + * O_CREAT - the queue will get created if it does not already exist. + * O_RDONLY - we are only planning to write to the queue. + * + * Open the queue, and create it if the sending process hasn't + * already created it. + */ + + mqfd = mq_open("testmq", O_RDONLY|O_CREAT, 0666, &attr); + if (mqfd < 0) + { + printf("receiver_thread: ERROR mq_open failed\n"); + pthread_exit((pthread_addr_t)1); + } + + /* Perform the receive TEST_RECEIVE_NMSGS times */ + + for (i = 0; i < TEST_RECEIVE_NMSGS; i++) + { + struct timespec ts; + int status = clock_gettime(CLOCK_REALTIME, &ts); + if (status != 0) + { + printf("sender_thread: ERROR clock_gettime failed\n"); + } + ts.tv_sec += 5; + + /* The first TEST_SEND_NMSGS-1 send should succeed. The last + * one should fail with errno == ETIMEDOUT + */ + + memset(msg_buffer, 0xaa, TEST_MSGLEN); + nbytes = mq_timedreceive(mqfd, msg_buffer, TEST_MSGLEN, 0, &ts); + if (nbytes < 0) + { + if (i == TEST_SEND_NMSGS-1 && errno == ETIMEDOUT) + { + printf("receiver_thread: Receive %d timed out as expected\n", i); + } + else + { + printf("receiver_thread: ERROR mq_timedreceive failure=%d on msg %d\n", errno, i); + nerrors++; + } + } + else if (nbytes != TEST_MSGLEN) + { + printf("receiver_thread: mq_timedreceive return bad size %d on msg %d\n", nbytes, i); + nerrors++; + } + else if (memcmp(TEST_MESSAGE, msg_buffer, nbytes) != 0) + { + int j; + + printf("receiver_thread: mq_timedreceive returned corrupt message on msg %d\n", i); + printf("receiver_thread: i Expected Received\n"); + + for (j = 0; j < TEST_MSGLEN-1; j++) + { + if (isprint(msg_buffer[j])) + { + printf("receiver_thread: %2d %02x (%c) %02x (%c)\n", + j, TEST_MESSAGE[j], TEST_MESSAGE[j], msg_buffer[j], msg_buffer[j]); + } + else + { + printf("receiver_thread: %2d %02x (%c) %02x\n", + j, TEST_MESSAGE[j], TEST_MESSAGE[j], msg_buffer[j]); + } + } + printf("receiver_thread: %2d 00 %02x\n", + j, msg_buffer[j]); + } + else if (i == TEST_SEND_NMSGS-1) + { + printf("receiver_thread: ERROR mq_timedreceive of msg %d succeeded\n", i); + nerrors++; + } + else + { + printf("receiver_thread: mq_timedreceive succeeded on msg %d\n", i); + } + } + + /* Close the queue and return success */ + + if (mq_close(mqfd) < 0) + { + printf("receiver_thread: ERROR mq_close failed\n"); + nerrors++; + } + + /* Destroy the queue */ + + if (mq_unlink("testmq") < 0) + { + printf("receiver_thread: ERROR mq_close failed\n"); + nerrors++; + } + + printf("receiver_thread: returning nerrors=%d\n", nerrors); + FFLUSH(); + pthread_exit((pthread_addr_t)nerrors); + return (pthread_addr_t)nerrors; +} + +void timedmqueue_test(void) +{ + pthread_t sender; + pthread_t receiver; + void *result; + pthread_attr_t attr; + int status; + + /* Start the sending thread at the default priority */ + + printf("timedmqueue_test: Starting sender\n"); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("timedmqueue_test: pthread_attr_init failed, status=%d\n", status); + } + + status = pthread_attr_setstacksize(&attr, STACKSIZE); + if (status != 0) + { + printf("timedmqueue_test: pthread_attr_setstacksize failed, status=%d\n", status); + } + + status = pthread_create(&sender, &attr, sender_thread, NULL); + if (status != 0) + { + printf("timedmqueue_test: pthread_create failed, status=%d\n", status); + } + + /* Wait for the sending thread to complete */ + + printf("timedmqueue_test: Waiting for sender to complete\n"); + pthread_join(sender, &result); + if (result != (void*)0) + { + printf("timedmqueue_test: ERROR sender thread exited with %d errors\n", (int)result); + } + + /* Start the receiving thread at the default priority */ + + printf("timedmqueue_test: Starting receiver\n"); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("timedmqueue_test: pthread_attr_init failed, status=%d\n", status); + } + + status = pthread_attr_setstacksize(&attr, STACKSIZE); + if (status != 0) + { + printf("timedmqueue_test: pthread_attr_setstacksize failed, status=%d\n", status); + } + + status = pthread_create(&receiver, &attr, receiver_thread, NULL); + if (status != 0) + { + printf("timedmqueue_test: pthread_create failed, status=%d\n", status); + } + + /* Wait for the receiving thread to complete */ + + printf("timedmqueue_test: Waiting for receiver to complete\n"); + pthread_join(receiver, &result); + if (result != (void*)0) + { + printf("timedmqueue_test: ERROR receiver thread exited with %d errors\n", (int)result); + } + + printf("timedmqueue_test: Test complete\n"); +} + + diff --git a/apps/examples/ostest/timedwait.c b/apps/examples/ostest/timedwait.c new file mode 100644 index 000000000..fc381ddda --- /dev/null +++ b/apps/examples/ostest/timedwait.c @@ -0,0 +1,195 @@ +/*********************************************************************** + * examples/ostest/timedwait.c + * + * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ***********************************************************************/ + +/************************************************************************** + * Included Files + **************************************************************************/ + +#include <stdio.h> +#include <time.h> +#include <pthread.h> +#include <unistd.h> +#include <errno.h> + +#include "ostest.h" + +/************************************************************************** + * Private Definitions + **************************************************************************/ + +/************************************************************************** + * Private Data + **************************************************************************/ + +static pthread_mutex_t mutex; +static pthread_cond_t cond; + +/************************************************************************** + * Private Functions + **************************************************************************/ + +static void *thread_waiter(void *parameter) +{ + struct timespec ts; + int status; + + /* Take the mutex */ + + printf("thread_waiter: Taking mutex\n"); + status = pthread_mutex_lock(&mutex); + if (status != 0) + { + printf("thread_waiter: ERROR pthread_mutex_lock failed, status=%d\n", status); + } + + printf("thread_waiter: Starting 5 second wait for condition\n"); + + status = clock_gettime(CLOCK_REALTIME, &ts); + if (status != 0) + { + printf("thread_waiter: ERROR clock_gettime failed\n"); + } + ts.tv_sec += 5; + + /* The wait -- no-one is ever going to awaken us */ + + status = pthread_cond_timedwait(&cond, &mutex, &ts); + if (status != 0) + { + if (status == ETIMEDOUT) + { + printf("thread_waiter: pthread_cond_timedwait timed out\n"); + } + else + { + printf("thread_waiter: ERROR pthread_cond_timedwait failed, status=%d\n", status); + } + } + else + { + printf("thread_waiter: ERROR pthread_cond_timedwait returned without timeout, status=%d\n", status); + } + + /* Release the mutex */ + + printf("thread_waiter: Releasing mutex\n"); + status = pthread_mutex_unlock(&mutex); + if (status != 0) + { + printf("thread_waiter: ERROR pthread_mutex_unlock failed, status=%d\n", status); + } + + printf("thread_waiter: Exit with status 0x12345678\n"); + pthread_exit((pthread_addr_t)0x12345678); + return NULL; +} + +/************************************************************************** + * Public Definitions + **************************************************************************/ + +void timedwait_test(void) +{ + pthread_t waiter; + pthread_attr_t attr; + struct sched_param sparam; + void *result; + int prio_max; + int status; + + /* Initialize the mutex */ + + printf("thread_waiter: Initializing mutex\n"); + status = pthread_mutex_init(&mutex, NULL); + if (status != 0) + { + printf("timedwait_test: ERROR pthread_mutex_init failed, status=%d\n", status); + } + + /* Initialize the condition variable */ + + printf("timedwait_test: Initializing cond\n"); + status = pthread_cond_init(&cond, NULL); + if (status != 0) + { + printf("timedwait_test: ERROR pthread_condinit failed, status=%d\n", status); + } + + /* Start the waiter thread at higher priority */ + + printf("timedwait_test: Starting waiter\n"); + status = pthread_attr_init(&attr); + if (status != 0) + { + printf("timedwait_test: pthread_attr_init failed, status=%d\n", status); + } + + prio_max = sched_get_priority_max(SCHED_FIFO); + status = sched_getparam (getpid(), &sparam); + if (status != 0) + { + printf("timedwait_test: sched_getparam failed\n"); + sparam.sched_priority = PTHREAD_DEFAULT_PRIORITY; + } + + sparam.sched_priority = (prio_max + sparam.sched_priority) / 2; + status = pthread_attr_setschedparam(&attr,&sparam); + if (status != OK) + { + printf("timedwait_test: pthread_attr_setschedparam failed, status=%d\n", status); + } + else + { + printf("timedwait_test: Set thread 2 priority to %d\n", sparam.sched_priority); + } + + status = pthread_create(&waiter, &attr, thread_waiter, NULL); + if (status != 0) + { + printf("timedwait_test: pthread_create failed, status=%d\n", status); + } + + printf("timedwait_test: Joining\n"); + FFLUSH(); + status = pthread_join(waiter, &result); + if (status != 0) + { + printf("timedwait_test: ERROR pthread_join failed, status=%d\n", status); + } + else + { + printf("timedwait_test: waiter exited with result=%p\n", result); + } +} diff --git a/apps/examples/pashello/Makefile b/apps/examples/pashello/Makefile new file mode 100644 index 000000000..44830eee2 --- /dev/null +++ b/apps/examples/pashello/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/examples/pashello/Makefile +# +# Copyright (C) 2008-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Pascal Add-On Example + +ASRCS = +CSRCS = pashello.c device.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/pashello/README.txt b/apps/examples/pashello/README.txt new file mode 100644 index 000000000..b976f18cf --- /dev/null +++ b/apps/examples/pashello/README.txt @@ -0,0 +1,34 @@ +README +^^^^^^ + +hello.pas + + This is a sample "Hello, World!" Pascal Program + +hello.pex + + This is the compiled, linked P-Code executable that results + when hello.pas is compiled. + +hello.h + + This file defines an initialized C array holds a copy of + hello.pex. This file as created by: + + xxd -i hello.pex >hello.h + +mkhello.sh + + This is a scripts that can be used to rebuild both hello.pex + and hello.h. + +device.c + + The hello.pex file must be provided to the interpreter as a file + in the file system. Normally this would be done using real storage + medium. In this example, we will use device.c: + + device.c implements a simple device driver. Reads from this device + will access the in-memory copy of hello.pex This device driver is + registered as /dev/pashello in the psuedo filesystem. + diff --git a/apps/examples/pashello/device.c b/apps/examples/pashello/device.c new file mode 100644 index 000000000..5f0038ad7 --- /dev/null +++ b/apps/examples/pashello/device.c @@ -0,0 +1,110 @@ +/**************************************************************************** + * examples/pashello/device.c + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Compilation Switches + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <string.h> +#include <errno.h> +#include <nuttx/fs.h> + +#include "hello.h" +#include "pashello.h" + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static ssize_t hello_read(struct file *, char *, size_t); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations hello_fops = +{ + 0, /* open */ + 0, /* close */ + hello_read, /* read */ + 0, /* write */ + 0, /* seek */ + 0, /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + 0 /* poll */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static ssize_t hello_read(struct file *filep, char *buffer, size_t len) +{ + off_t offset = filep->f_pos; /* Start read position */ + ssize_t nread = 0; /* Bytes read -- assume EOF */ + + /* Make sure that the offset is within the .pex file */ + + if (offset < hello_pex_len) + { + /* Make sure the read does not extend beyond the .pex file */ + + nread = len; + if (nread + offset > hello_pex_len) + { + nread = hello_pex_len - offset; + } + memcpy(buffer, &hello_pex[offset], nread); + filep->f_pos += nread; + } + return nread; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void hello_register(void) +{ + (void)register_driver("/dev/hello", &hello_fops, 0444, NULL); +} diff --git a/apps/examples/pashello/hello.h b/apps/examples/pashello/hello.h new file mode 100644 index 000000000..818e5e4a5 --- /dev/null +++ b/apps/examples/pashello/hello.h @@ -0,0 +1,23 @@ +unsigned char hello_pex[] = { + 0x50, 0x4f, 0x46, 0x46, 0x01, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x11, 0x01, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, + 0x00, 0x00, 0x00, 0x0f, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x04, + 0x06, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, + 0x00, 0x00, 0x00, 0x38, 0xb1, 0x00, 0x00, 0x74, 0x0e, 0xf9, 0x00, 0x00, + 0x25, 0xb5, 0xff, 0xfc, 0xf9, 0x00, 0x00, 0x20, 0x3f, 0x48, 0x65, 0x6c, + 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x21, 0x21, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x48, 0x45, 0x4c, + 0x4c, 0x4f, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e, 0x70, 0x61, 0x73, + 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x72, 0x6f, 0x64, 0x61, + 0x74, 0x61, 0x00, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x74, 0x61, 0x62, 0x00, + 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x6e, 0x6f, 0x00, 0x2e, 0x73, 0x74, 0x72, + 0x74, 0x61, 0x62, 0x00 +}; +unsigned int hello_pex_len = 232; diff --git a/apps/examples/pashello/hello.pas b/apps/examples/pashello/hello.pas new file mode 100644 index 000000000..fe137f1b6 --- /dev/null +++ b/apps/examples/pashello/hello.pas @@ -0,0 +1,5 @@ +program hello(output); +begin + writeln('Hello world!!!'); +end. + diff --git a/apps/examples/pashello/hello.pex b/apps/examples/pashello/hello.pex Binary files differnew file mode 100644 index 000000000..c23610598 --- /dev/null +++ b/apps/examples/pashello/hello.pex diff --git a/apps/examples/pashello/mkhello.sh b/apps/examples/pashello/mkhello.sh new file mode 100755 index 000000000..716a7e96d --- /dev/null +++ b/apps/examples/pashello/mkhello.sh @@ -0,0 +1,141 @@ +#!/bin/bash +############################################################################ +# examples/pashello/mkhello.sh +# +# Copyright (C) 2008 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ +#set -x + +BINDIR=$1 +WD=`pwd` + +PASCAL=${BINDIR}/pascal +POPT=${BINDIR}/popt +PLINK=${BINDIR}/plink +PRUN=${BINDIR}/prun + +PASFILENAME=hello.pas +OUFILE=hello.h +STRSTKSZ=1024 + +function sanity_check () +{ + if [ ! -f "${WD}/${PASFILENAME}" ]; then + echo "ERROR: Source ${PASFILENAME} does not exist in this directory" + exit 1 + fi + if [ -z "${BINDIR}" ]; then + echo "ERROR: Path to the pascal bin/ directory not provided" + exit 1 + fi + if [ ! -d "${BINDIR}" ]; then + echo "ERROR: Tool ${BINDIR} does not exist" + exit 1 + fi + if [ ! -x "${PASCAL}" ]; then + echo "ERROR: Executable ${PASCAL} does not exist" + exit 1 + fi + if [ ! -x "${POPT}" ]; then + echo "ERROR: Executable ${POPT} does not exist" + exit 1 + fi + if [ ! -x "${PLINK}" ]; then + echo "ERROR: Executable ${PLINK} does not exist" + exit 1 + fi + if [ ! -x "${PRUN}" ]; then + echo "ERROR: Executable ${PRUN} does not exist" + exit 1 + fi +} + +function compile_hello () +{ + PASOPTS= + ${PASCAL} ${PASOPTS} ${PASFILENAME} 2>&1 || rm -f hello.o1 + if [ -f hello.err ] ; then + cat hello.err | grep Line + fi + if [ ! -f hello.o1 ] ; then + echo "Compilation failed" + else + POPTOPTS= + ${POPT} ${POPTOPTS} hello.o1 2>&1 + ${PLINK} hello.o hello.pex 2>&1 + fi +} + +function test_program () +{ + if [ "${CONFIG_REGM}" == "y" ]; then + echo "Don't know how to run REGM programs yet" + else + echo "Using string stack size = ${STRSTKSZ}" + PRUNOPTS="-t ${STRSTKSZ}" + + if [ ! -f hello.pex ]; then + echo "No p-code executable" + else + if [ -f hello.inp ] ; then + ${PRUN} ${PRUNOPTS} hello.pex 2>&1 <hello.inp + else + ${PRUN} ${PRUNOPTS} hello.pex 2>&1 + fi + fi + fi +} + +function test_hello () +{ + echo "Using string stack size = ${STRSTKSZ}" + PRUNOPTS="-t ${STRSTKSZ}" + + if [ ! -f hello.pex ]; then + echo "No p-code executable" + exit 1 + else + ${PRUN} ${PRUNOPTS} hello.pex + fi +} + +function make_include () +{ + xxd -i hello.pex >hello.h +} + +sanity_check +compile_hello +rm *.o *.o1 *.lst *.err +test_hello +make_include + diff --git a/apps/examples/pashello/pashello.c b/apps/examples/pashello/pashello.c new file mode 100644 index 000000000..ae19c94f5 --- /dev/null +++ b/apps/examples/pashello/pashello.c @@ -0,0 +1,133 @@ +/**************************************************************************** + * examples/pashello/pashello.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <debug.h> + +#include "apps/pcode/insn/pexec.h" +#include "apps/pcode/pedefs.h" +#include "pashello.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifndef CONFIG_PASHELLO_VARSTACKSIZE +# define CONFIG_PASHELLO_VARSTACKSIZE 1024 +#endif + +#ifndef CONFIG_PASHELLO_STRSTACKSIZE +# define CONFIG_PASHELLO_STRSTACKSIZE 128 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: prun + * + * Description: + * This function executes the P-Code program until a stopping condition + * is encountered. + * + ****************************************************************************/ + +static void prun(FAR struct pexec_s *st) +{ + int errcode; + + for (;;) + { + /* Execute the instruction; Check for exceptional conditions */ + + errcode = pexec(st); + if (errcode != eNOERROR) break; + } + + if (errcode != eEXIT) + { + printf("Runtime error 0x%02x -- Execution Stopped\n", errcode); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, FAR char *argv[]) +{ + FAR struct pexec_s *st; + + /* Register the /dev/hello driver */ + + hello_register(); + + /* Load the POFF file */ + + st = pload("/dev/hello", CONFIG_PASHELLO_VARSTACKSIZE, CONFIG_PASHELLO_STRSTACKSIZE); + if (!st) + { + fprintf(stderr, "user_start: ERROR: Could not load /dev/hello\n"); + exit(1); + } + printf("user_start: /dev/hello Loaded\n"); + printf("user_start: Interpreter started:\n"); + + /* And start program execution */ + + prun(st); + + /* Clean up resources used by the interpreter */ + + printf("user_start: Interpreter terminated"); + pexec_release(st); + return 0; +} diff --git a/apps/examples/pashello/pashello.h b/apps/examples/pashello/pashello.h new file mode 100644 index 000000000..ad206261e --- /dev/null +++ b/apps/examples/pashello/pashello.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * examples/pashello/pashello.h + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_PASHELLO_H +#define __EXAMPLES_PASHELLO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Defined in device.c */ + +extern void hello_register(void); + +#endif /* __EXAMPLES_PASHELLO_H */ diff --git a/apps/examples/pipe/Makefile b/apps/examples/pipe/Makefile new file mode 100644 index 000000000..3bcc9b5f7 --- /dev/null +++ b/apps/examples/pipe/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/examples/pipe/Makefile +# +# Copyright (C) 2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Pipe Example + +ASRCS = +CSRCS = pipe_main.c transfer_test.c interlock_test.c redirect_test.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/pipe/interlock_test.c b/apps/examples/pipe/interlock_test.c new file mode 100644 index 000000000..e049a65f6 --- /dev/null +++ b/apps/examples/pipe/interlock_test.c @@ -0,0 +1,224 @@ +/**************************************************************************** + * examples/pipe/interlock_test.c + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <sys/stat.h> + +#include <sys/types.h> + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include "pipe.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: null_writer + ****************************************************************************/ + +static void *null_writer(pthread_addr_t pvarg) +{ + int fd; + + /* Wait a bit */ + + printf("null_writer: started -- sleeping\n"); + sleep(5); + + /* Then open the FIFO for write access */ + + printf("null_writer: Opening FIFO for write access\n"); + fd = open(FIFO_PATH2, O_WRONLY); + if (fd < 0) + { + fprintf(stderr, "null_writer: Failed to open FIFO %s for writing, errno=%d\n", + FIFO_PATH2, errno); + return (void*)1; + } + + /* Wait a bit more */ + + printf("null_writer: Opened %s for writing -- sleeping\n", FIFO_PATH2); + sleep(5); + + /* Then close the FIFO */ + + printf("null_writer: Closing %s\n", FIFO_PATH2); + if (close(fd) != 0) + { + fprintf(stderr, "null_writer: close failed: %d\n", errno); + } + sleep(5); + + printf("null_writer: Returning success\n"); + return (void*)0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: interlock_test + ****************************************************************************/ + +int interlock_test(void) +{ + pthread_t writerid; + void *value; + char data[16]; + ssize_t nbytes; + int fd; + int ret; + + /* Create a FIFO */ + + ret = mkfifo(FIFO_PATH2, 0666); + if (ret < 0) + { + fprintf(stderr, "interlock_test: mkfifo failed with errno=%d\n", errno); + return 1; + } + + /* Start the null_writer_thread */ + + printf("interlock_test: Starting null_writer thread\n"); + ret = pthread_create(&writerid, NULL, null_writer, (pthread_addr_t)NULL); + if (ret != 0) + { + fprintf(stderr, "interlock_test: Failed to create null_writer thread, error=%d\n", ret); + ret = 2; + goto errout_with_fifo; + } + + /* Open one end of the FIFO for reading. This open call should block until the + * null_writer thread opens the other end of the FIFO for writing. + */ + + printf("interlock_test: Opening FIFO for read access\n"); + fd = open(FIFO_PATH2, O_RDONLY); + if (fd < 0) + { + fprintf(stderr, "interlock_test: Failed to open FIFO %s for reading, errno=%d\n", + FIFO_PATH2, errno); + ret = 3; + goto errout_with_thread; + } + + /* Attempt to read one byte from the FIFO. This should return end-of-file because + * the null_writer closes the FIFO without writing anything. + */ + + printf("interlock_test: Reading from %s\n", FIFO_PATH2); + nbytes = read(fd, data, 16); + if (nbytes < 0 ) + { + fprintf(stderr, "interlock_test: read failed, errno=%d\n", errno); + ret = 4; + goto errout_with_file; + } + else if (ret != 0) + { + fprintf(stderr, "interlock_test: Read %d bytes of data -- aborting: %d\n", nbytes); + ret = 5; + goto errout_with_file; + } + + /* Close the file */ + + printf("interlock_test: Closing %s\n", FIFO_PATH2); + if (close(fd) != 0) + { + fprintf(stderr, "interlock_test: close failed: %d\n", errno); + } + + /* Wait for null_writer thread to complete */ + + printf("interlock_test: Waiting for null_writer thread\n"); + ret = pthread_join(writerid, &value); + if (ret != 0) + { + fprintf(stderr, "interlock_test: pthread_join failed, error=%d\n", ret); + ret = 6; + goto errout_with_fifo; + } + else + { + printf("interlock_test: writer returned %d\n", (int)value); + if (value != (void*)0) + { + ret = 7; + goto errout_with_fifo; + } + } + + /* unlink(FIFO_PATH2); */ + printf("interlock_test: Returning success\n"); + return 0; + +errout_with_file: + if (close(fd) != 0) + { + fprintf(stderr, "interlock_test: close failed: %d\n", errno); + } +errout_with_thread: + pthread_detach(writerid); + pthread_cancel(writerid); +errout_with_fifo: + /* unlink(FIFO_PATH2); */ + printf("interlock_test: Returning %d\n", ret); + return ret; +} diff --git a/apps/examples/pipe/pipe.h b/apps/examples/pipe/pipe.h new file mode 100644 index 000000000..2c18fd868 --- /dev/null +++ b/apps/examples/pipe/pipe.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * examples/pipe/pipe.h + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_PIPE_PIPE_H +#define __EXAMPLES_PIPE_PIPE_H + +/**************************************************************************** + * Compilation Switches + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define FIFO_PATH1 "/tmp/testfifo-1" +#define FIFO_PATH2 "/tmp/testfifo-2" + +#ifndef CONFIG_EXAMPLES_PIPE_STACKSIZE +# define CONFIG_EXAMPLES_PIPE_STACKSIZE 1024 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +extern int transfer_test(int fdin, int fdout); +extern int interlock_test(void); +extern int redirection_test(void); + +#endif /* __EXAMPLES_PIPE_PIPE_H */ diff --git a/apps/examples/pipe/pipe_main.c b/apps/examples/pipe/pipe_main.c new file mode 100644 index 000000000..1f0f73032 --- /dev/null +++ b/apps/examples/pipe/pipe_main.c @@ -0,0 +1,189 @@ +/**************************************************************************** + * examples/pipe/pipe_main.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/stat.h> +#include <stdio.h> +#include <unistd.h> +#include <sched.h> +#include <fcntl.h> +#include <errno.h> + +#include "pipe.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + int filedes[2]; + int ret; + + /* Test FIFO logic */ + + printf("\nuser_start: Performing FIFO test\n"); + ret = mkfifo(FIFO_PATH1, 0666); + if (ret < 0) + { + fprintf(stderr, "user_start: mkfifo failed with errno=%d\n", errno); + return 1; + } + + /* Open one end of the FIFO for reading and the other end for writing. NOTE: + * the following might not work on most FIFO implementations because the attempt + * to open just one end of the FIFO for writing might block. The NuttX FIFOs block + * only on open for read-only (see interlock_test()). + */ + + filedes[1] = open(FIFO_PATH1, O_WRONLY); + if (filedes[1] < 0) + { + fprintf(stderr, "user_start: Failed to open FIFO %s for writing, errno=%d\n", + FIFO_PATH1, errno); + return 2; + } + + filedes[0] = open(FIFO_PATH1, O_RDONLY); + if (filedes[0] < 0) + { + fprintf(stderr, "user_start: Failed to open FIFO %s for reading, errno=%d\n", + FIFO_PATH1, errno); + if (close(filedes[1]) != 0) + { + fprintf(stderr, "user_start: close failed: %d\n", errno); + } + return 3; + } + + /* Then perform the test using those file descriptors */ + + ret = transfer_test(filedes[0], filedes[1]); + if (close(filedes[0]) != 0) + { + fprintf(stderr, "user_start: close failed: %d\n", errno); + } + if (close(filedes[1]) != 0) + { + fprintf(stderr, "user_start: close failed: %d\n", errno); + } + /* unlink(FIFO_PATH1); fails */ + + if (ret != 0) + { + fprintf(stderr, "user_start: FIFO test FAILED (%d)\n", ret); + return 4; + } + printf("user_start: FIFO test PASSED\n"); + + /* Test PIPE logic */ + + printf("\nuser_start: Performing pipe test\n"); + ret = pipe(filedes); + if (ret < 0) + { + fprintf(stderr, "user_start: pipe failed with errno=%d\n", errno); + return 5; + } + + /* Then perform the test using those file descriptors */ + + ret = transfer_test(filedes[0], filedes[1]); + if (close(filedes[0]) != 0) + { + fprintf(stderr, "user_start: close failed: %d\n", errno); + } + if (close(filedes[1]) != 0) + { + fprintf(stderr, "user_start: close failed: %d\n", errno); + } + + if (ret != 0) + { + fprintf(stderr, "user_start: PIPE test FAILED (%d)\n", ret); + return 6; + } + printf("user_start: PIPE test PASSED\n"); + + /* Perform the FIFO interlock test */ + + printf("\nuser_start: Performing pipe interlock test\n"); + ret = interlock_test(); + if (ret != 0) + { + fprintf(stderr, "user_start: FIFO interlock test FAILED (%d)\n", ret); + return 7; + } + printf("user_start: PIPE interlock test PASSED\n"); + + /* Perform the pipe redirection test */ + + printf("\nuser_start: Performing redirection test\n"); + ret = redirection_test(); + if (ret != 0) + { + fprintf(stderr, "user_start: FIFO redirection test FAILED (%d)\n", ret); + return 7; + } + printf("user_start: PIPE redirection test PASSED\n"); + + fflush(stdout); + return 0; +} diff --git a/apps/examples/pipe/redirect_test.c b/apps/examples/pipe/redirect_test.c new file mode 100644 index 000000000..45e86c356 --- /dev/null +++ b/apps/examples/pipe/redirect_test.c @@ -0,0 +1,326 @@ +/**************************************************************************** + * examples/pipe/redirect_test.c + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sched.h> +#include <semaphore.h> +#include <errno.h> + +#include "pipe.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define READ_SIZE 37 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static sem_t g_rddone; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: redirect_reader + ****************************************************************************/ + +static int redirect_reader(int argc, char *argv[]) +{ + char buffer[READ_SIZE]; + int fdin; + int fdout; + int ret; + int nbytes = 0; + + printf("redirect_reader: started with fdin=%s\n", argv[1]); + + /* Convert the fdin to binary */ + + fdin = atoi(argv[1]); + fdout = atoi(argv[2]); + + /* Close fdout -- we don't need it */ + + ret = close(fdout); + if (ret != 0) + { + fprintf(stderr, "redirect_reader: failed to close fdout=%d\n", fdout); + return 1; + } + + /* Re-direct the fdin to stdin */ + + ret = dup2(fdin, 0); + if (ret != 0) + { + fprintf(stderr, "redirect_reader: dup2 failed: %d\n", errno); + close(fdin); + return 2; + } + + /* Close the original file descriptor */ + + ret = close(fdin); + if (ret != 0) + { + fprintf(stderr, "redirect_reader: failed to close fdin=%d\n", fdin); + return 3; + } + + /* Then read from stdin until we hit the end of file */ + + fflush(stdout); + for (;;) + { + /* Read from stdin */ + + ret = read(0, buffer, READ_SIZE); + if (ret < 0 ) + { + fprintf(stderr, "redirect_reader: read failed, errno=%d\n", errno); + return 4; + } + else if (ret == 0) + { + break; + } + nbytes += ret; + + /* Echo to stdout */ + + ret = write(1, buffer, ret); + if (ret < 0) + { + fprintf(stderr, "redirect_reader: read failed, errno=%d\n", errno); + return 5; + } + } + + printf("redirect_reader: %d bytes read\n", nbytes); + ret = close(0); + if (ret != 0) + { + fprintf(stderr, "redirect_reader: failed to close fd=0\n"); + return 6; + } + + sem_post(&g_rddone); + printf("redirect_reader: Returning success\n"); + return 0; +} + +/**************************************************************************** + * Name: redirect_writer + ****************************************************************************/ + +static int redirect_writer(int argc, char *argv[]) +{ + int fdin; + int fdout; + int nbytes = 0; + int ret; + + fprintf(stderr, "redirect_writer: started with fdout=%s\n", argv[2]); + + /* Convert the fdout to binary */ + + fdin = atoi(argv[1]); + fdout = atoi(argv[2]); + + /* Close fdin -- we don't need it */ + + ret = close(fdin); + if (ret != 0) + { + fprintf(stderr, "redirect_reader: failed to close fdin=%d\n", fdin); + return 1; + } + + /* Re-direct the fdout to stdout */ + + ret = dup2(fdout, 1); + if (ret != 0) + { + fprintf(stderr, "redirect_writer: dup2 failed: %d\n", errno); + return 2; + } + + /* Close the original file descriptor */ + + ret = close(fdout); + if (ret != 0) + { + fprintf(stderr, "redirect_reader: failed to close fdout=%d\n", fdout); + return 3; + } + + /* Then write a bunch of stuff to stdout */ + + fflush(stderr); + nbytes += printf("\nFour score and seven years ago our fathers brought forth on this continent a new nation,\n"); + nbytes += printf("conceived in Liberty, and dedicated to the proposition that all men are created equal.\n"); + nbytes += printf("\nNow we are engaged in a great civil war, testing whether that nation, or any nation, so\n"); + nbytes += printf("conceived and so dedicated, can long endure. We are met on a great battle-field of that war.\n"); + nbytes += printf("We have come to dedicate a portion of that field, as a final resting place for those who here\n"); + nbytes += printf("gave their lives that that nation might live. It is altogether fitting and proper that we\n"); + nbytes += printf("should do this.\n"); + nbytes += printf("\nBut, in a larger sense, we can not dedicate - we can not consecrate - we can not hallow - this ground.\n"); + nbytes += printf("The brave men, living and dead, who struggled here, have consecrated it, far above our poor power\n"); + nbytes += printf("to add or detract. The world will little note, nor long remember what we say here, but it can\n"); + nbytes += printf("never forget what they did here. It is for us the living, rather, to be dedicated here to the\n"); + nbytes += printf("unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to\n"); + nbytes += printf("be here dedicated to the great task remaining before us - that from these honored dead we take\n"); + nbytes += printf("increased devotion to that cause for which they gave the last full measure of devotion - that we\n"); + nbytes += printf("here highly resolve that these dead shall not have died in vain - that this nation, under God,\n"); + nbytes += printf("shall have a new birth of freedom - and that government of the people, by the people, for the\n"); + nbytes += printf("people, shall not perish from the earth.\n\n"); + fflush(stdout); + + fprintf(stderr, "redirect_writer: %d bytes written\n", nbytes); + + ret = close(1); + if (ret != 0) + { + fprintf(stderr, "redirect_writer: failed to close fd=1\n"); + return 4; + } + + fprintf(stderr, "redirect_writer: Returning success\n"); + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: redirection_test + ****************************************************************************/ + +int redirection_test(void) +{ + const char *argv[3]; + char buffer1[8]; + char buffer2[8]; + int readerid; + int writerid; + int filedes[2]; + int ret; + + sem_init(&g_rddone, 0, 0); + + /* Create the pipe */ + + ret = pipe(filedes); + if (ret < 0) + { + fprintf(stderr, "redirection_test: pipe failed with errno=%d\n", errno); + return 5; + } + + sprintf(buffer1, "%d", filedes[0]); + argv[0] = buffer1; + sprintf(buffer2, "%d", filedes[1]); + argv[1] = buffer2; + argv[2] = NULL; + + /* Start redirect_reader thread */ + + printf("redirection_test: Starting redirect_reader task with fd=%d\n", filedes[0]); + readerid = task_create("redirect_reader", 50, CONFIG_EXAMPLES_PIPE_STACKSIZE, redirect_reader, argv); + if (readerid < 0) + { + fprintf(stderr, "redirection_test: Failed to create redirect_writer task: %d\n", errno); + return 1; + } + + /* Start redirect_writer task */ + + printf("redirection_test: Starting redirect_writer task with fd=%d\n", filedes[1]); + writerid = task_create("redirect_writer", 50, CONFIG_EXAMPLES_PIPE_STACKSIZE, redirect_writer, argv); + if (writerid < 0) + { + fprintf(stderr, "redirection_test: Failed to create redirect_writer task: %d\n", errno); + ret = task_delete(readerid); + if (ret != 0) + { + fprintf(stderr, "redirection_test: Failed to delete redirect_reader task %d\n", errno); + } + return 2; + } + + /* We should be able to close the pipe file descriptors now. */ + + if (close(filedes[0]) != 0) + { + fprintf(stderr, "user_start: close failed: %d\n", errno); + } + if (close(filedes[1]) != 0) + { + fprintf(stderr, "user_start: close failed: %d\n", errno); + } + + if (ret != 0) + { + fprintf(stderr, "user_start: PIPE test FAILED (%d)\n", ret); + return 6; + } + + /* Wait for redirect_writer thread to complete */ + + printf("redirection_test: Waiting...\n"); + fflush(stdout); + sem_wait(&g_rddone); + + printf("redirection_test: returning %d\n", ret); + return ret; +} + diff --git a/apps/examples/pipe/transfer_test.c b/apps/examples/pipe/transfer_test.c new file mode 100644 index 000000000..cb8cad04a --- /dev/null +++ b/apps/examples/pipe/transfer_test.c @@ -0,0 +1,242 @@ +/**************************************************************************** + * examples/pipe/transfer_test.c + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> + +#include "pipe.h" + +/**************************************************************************** + * Pre-proecessor Definitions + ****************************************************************************/ + +#define MAX_BYTE 13 + +#define WRITE_SIZE MAX_BYTE +#define NWRITES 1400 +#define NWRITE_BYTES (NWRITES * WRITE_SIZE) + +#define READ_SIZE (2*MAX_BYTE) +#define NREADS (NWRITES / 2) +#define NREAD_BYTES NWRITE_BYTES + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: transfer_reader + ****************************************************************************/ + +static void *transfer_reader(pthread_addr_t pvarg) +{ + char buffer[READ_SIZE]; + int fd = (int)pvarg; + int ret; + int nbytes; + int value; + int ndx; + + printf("transfer_reader: started\n"); + for (nbytes = 0, value = 0; nbytes < NREAD_BYTES;) + { + ret = read(fd, buffer, READ_SIZE); + if (ret < 0 ) + { + fprintf(stderr, "transfer_reader: read failed, errno=%d\n", errno); + return (void*)1; + } + else if (ret == 0) + { + if (nbytes < NREAD_BYTES) + { + fprintf(stderr, "transfer_reader: Too few bytes read -- aborting: %d\n", nbytes); + return (void*)2; + } + break; + } + for (ndx = 0; ndx < ret; ndx++) + { + if (value >= WRITE_SIZE) + { + value = 0; + } + if (buffer[ndx] != value) + { + fprintf(stderr, "transfer_reader: Byte %d, expected %d, found %d\n", + nbytes + ndx, value, buffer[ndx]); + return (void*)3; + } + value++; + } + nbytes += ret; + if (nbytes > NREAD_BYTES) + { + fprintf(stderr, "transfer_reader: Too many bytes read -- aborting: %d\n", nbytes); + return (void*)4; + } + } + printf("transfer_reader: %d bytes read\n", nbytes); + return (void*)0; +} + +/**************************************************************************** + * Name: transfer_writer + ****************************************************************************/ + +static void *transfer_writer(pthread_addr_t pvarg) +{ + char buffer[WRITE_SIZE]; + int fd = (int)pvarg; + int ret; + int i; + + printf("transfer_writer: started\n"); + for (i = 0; i < WRITE_SIZE; i++) + { + buffer[i] = i; + } + + for (i = 0; i < NWRITES; i++) + { + ret = write(fd, buffer, WRITE_SIZE); + if (ret < 0 ) + { + fprintf(stderr, "transfer_writer: write failed, errno=%d\n", errno); + return (void*)1; + } + else if (ret != WRITE_SIZE) + { + fprintf(stderr, "transfer_writer: Unexpected write size=%d\n", ret); + return (void*)2; + } + } + printf("transfer_writer: %d bytes written\n", NWRITE_BYTES); + return (void*)0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: transfer_test + ****************************************************************************/ + +int transfer_test(int fdin, int fdout) +{ + pthread_t readerid; + pthread_t writerid; + void *value; + int tmp; + int ret; + + /* Start transfer_reader thread */ + + printf("transfer_test: Starting transfer_reader thread\n"); + ret = pthread_create(&readerid, NULL, transfer_reader, (pthread_addr_t)fdin); + if (ret != 0) + { + fprintf(stderr, "transfer_test: Failed to create transfer_reader thread, error=%d\n", ret); + return 1; + } + + /* Start transfer_writer thread */ + + printf("transfer_test: Starting transfer_writer thread\n"); + ret = pthread_create(&writerid, NULL, transfer_writer, (pthread_addr_t)fdout); + if (ret != 0) + { + fprintf(stderr, "transfer_test: Failed to create transfer_writer thread, error=%d\n", ret); + pthread_detach(readerid); + ret = pthread_cancel(readerid); + if (ret != 0) + { + fprintf(stderr, "transfer_test: Failed to cancel transfer_reader thread, error=%d\n", ret); + } + return 2; + } + + /* Wait for transfer_writer thread to complete */ + + printf("transfer_test: Waiting for transfer_writer thread\n"); + ret = pthread_join(writerid, &value); + if (ret != 0) + { + fprintf(stderr, "transfer_test: pthread_join failed, error=%d\n", ret); + } + else + { + ret = (int)value; + printf("transfer_test: transfer_writer returned %d\n", ret); + } + + /* Wait for transfer_reader thread to complete */ + + printf("transfer_test: Waiting for transfer_reader thread\n"); + tmp = pthread_join(readerid, &value); + if (tmp != 0) + { + fprintf(stderr, "transfer_test: pthread_join failed, error=%d\n", ret); + } + else + { + tmp = (int)value; + printf("transfer_test: transfer_reader returned %d\n", tmp); + } + + if (ret == 0) + { + ret = tmp; + } + printf("transfer_test: returning %d\n", ret); + return ret; +} + diff --git a/apps/examples/poll/Makefile b/apps/examples/poll/Makefile new file mode 100644 index 000000000..1c85d6f36 --- /dev/null +++ b/apps/examples/poll/Makefile @@ -0,0 +1,94 @@ +############################################################################ +# apps/examples/poll/Makefile +# +# Copyright (C) 2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Device Driver poll()/select() Example + +ASRCS = +CSRCS = poll_main.c poll_listener.c select_listener.c net_listener.c net_reader.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +# Register application +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend host + +-include Make.dep diff --git a/apps/examples/poll/Makefile.host b/apps/examples/poll/Makefile.host new file mode 100644 index 000000000..9d9daee27 --- /dev/null +++ b/apps/examples/poll/Makefile.host @@ -0,0 +1,54 @@ +############################################################################ +# apps/examples/poll/Makefile.host +# +# Copyright (C) 2008, 2009, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TOPDIR must be defined on the make command line + +include $(TOPDIR)/.config +include $(TOPDIR)/Make.defs + +SRC = host.c +BIN = host + +DEFINES = -DTARGETIP=\"$(TARGETIP)\" + +all: $(BIN) + +$(BIN): $(SRC) + $(HOSTCC) $(HOSTCFLAGS) $(DEFINES) $^ -o $@ + +clean: + @rm -f $(BIN) *~ .*.swp *.o + $(call CLEAN) + diff --git a/apps/examples/poll/host.c b/apps/examples/poll/host.c new file mode 100644 index 000000000..47f2c3e53 --- /dev/null +++ b/apps/examples/poll/host.c @@ -0,0 +1,166 @@ +/**************************************************************************** + * examples/poll/host.c + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/socket.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthread.h> +#include <string.h> +#include <errno.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#define pthread_addr_t void * +#include "poll_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef TARGETIP +# error TARGETIP not defined +#endif + +#define IOBUFFER_SIZE 80 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * main + ****************************************************************************/ + +int main(int argc, char **argv, char **envp) +{ + struct sockaddr_in myaddr; + char outbuf[IOBUFFER_SIZE]; + char inbuf[IOBUFFER_SIZE]; + int sockfd; + int len; + int nbytessent; + int nbytesrecvd; + int i; + + /* Create a new TCP socket */ + + sockfd = socket(PF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + { + message("client socket failure %d\n", errno); + goto errout_with_outbufs; + } + + /* Connect the socket to the server */ + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(LISTENER_PORT); + myaddr.sin_addr.s_addr = inet_addr(TARGETIP); + + message("client: Connecting to %s...\n", TARGETIP); + if (connect( sockfd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0) + { + message("client: connect failure: %d\n", errno); + goto errout_with_socket; + } + message("client: Connected\n"); + + /* Then send and receive messages */ + + for (i = 0; ; i++) + { + sprintf(outbuf, "Remote message %d", i); + len = strlen(outbuf); + + message("client: Sending '%s' (%d bytes)\n", outbuf, len); + nbytessent = send(sockfd, outbuf, len, 0); + message("client: Sent %d bytes\n", nbytessent); + + if (nbytessent < 0) + { + message("client: send failed: %d\n", errno); + goto errout_with_socket; + } + else if (nbytessent != len) + { + message("client: Bad send length: %d Expected: %d\n", nbytessent, len); + goto errout_with_socket; + } + + message("client: Receiving...\n"); + nbytesrecvd = recv(sockfd, inbuf, IOBUFFER_SIZE, 0); + + if (nbytesrecvd < 0) + { + message("client: recv failed: %d\n", errno); + goto errout_with_socket; + } + + inbuf[nbytesrecvd] = '\0'; + message("client: Received '%s' (%d bytes)\n", inbuf, nbytesrecvd); + + if (nbytesrecvd != len) + { + message("client: Bad recv length: %d Expected: %d\n", nbytesrecvd, len); + goto errout_with_socket; + } + else if (memcmp(inbuf, outbuf, len) != 0) + { + message("client: Received outbuf does not match sent outbuf\n"); + goto errout_with_socket; + } + + message("client: Sleeping\n"); + sleep(8); + } + + close(sockfd); + return 0; + +errout_with_socket: + close(sockfd); +errout_with_outbufs: + exit(1); +} diff --git a/apps/examples/poll/net_listener.c b/apps/examples/poll/net_listener.c new file mode 100644 index 000000000..4d425c608 --- /dev/null +++ b/apps/examples/poll/net_listener.c @@ -0,0 +1,428 @@ +/**************************************************************************** + * examples/poll/net_listener.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/stat.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <errno.h> +#include <debug.h> + +#include <net/if.h> +#include <apps/netutils/uiplib.h> + +#include "poll_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define IOBUFFER_SIZE 80 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct net_listener_s +{ + struct sockaddr_in addr; + fd_set master; + fd_set working; + char buffer[IOBUFFER_SIZE]; + int listensd; + int mxsd; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: net_closeclient + ****************************************************************************/ + +static bool net_closeclient(struct net_listener_s *nls, int sd) +{ + message("net_listener: Closing host side connection sd=%d\n", sd); + close(sd); + FD_CLR(sd, &nls->master); + + /* If we just closed the max SD, then search downward for the next biggest SD. */ + + while (FD_ISSET(nls->mxsd, &nls->master) == false) + { + nls->mxsd -= 1; + } + return true; +} + +/**************************************************************************** + * Name: net_incomingdata + ****************************************************************************/ + +static inline bool net_incomingdata(struct net_listener_s *nls, int sd) +{ + char *ptr; + int nbytes; + int ret; + + /* Read data from the socket */ + +#ifdef FIONBIO + for (;;) +#endif + { + message("net_listener: Read data from sd=%d\n", sd); + ret = recv(sd, nls->buffer, IOBUFFER_SIZE, 0); + if (ret < 0) + { + if (errno != EINTR) + { + message("net_listener: recv failed sd=%d: %d\n", sd, errno); + if (errno != EAGAIN) + { + net_closeclient(nls, sd); + return false; + } + } + } + else if (ret == 0) + { + message("net_listener: Client connection lost sd=%d\n", sd); + net_closeclient(nls, sd); + return false; + } + else + { + nls->buffer[ret]='\0'; + message("poll_listener: Read '%s' (%d bytes)\n", nls->buffer, ret); + + /* Echo the data back to the client */ + + for (nbytes = ret, ptr = nls->buffer; nbytes > 0; ) + { + ret = send(sd, ptr, nbytes, 0); + if (ret < 0) + { + if (errno != EINTR) + { + message("net_listener: Send failed sd=%d: \n", sd, errno); + net_closeclient(nls, sd); + return false; + } + } + else + { + nbytes -= ret; + ptr += ret; + } + } + } + } + return 0; +} + +/**************************************************************************** + * Name: net_connection + ****************************************************************************/ + +static inline bool net_connection(struct net_listener_s *nls) +{ + int sd; + + /* Loop until all connections have been processed */ + +#ifdef FIONBIO + for (;;) +#endif + { + message("net_listener: Accepting new connection on sd=%d\n", nls->listensd); + + sd = accept(nls->listensd, NULL, NULL); + if (sd < 0) + { + message("net_listener: accept failed: %d\n", errno); + + if (errno != EINTR) + { + return false; + } + } + else + { + /* Add the new connection to the master set */ + + message("net_listener: Connection accepted for sd=%d\n", sd); + + FD_SET(sd, &nls->master); + if (sd > nls->mxsd) + { + nls->mxsd = sd; + } + return true; + } + } + return false; +} + +/**************************************************************************** + * Name: net_mksocket + ****************************************************************************/ + +static inline bool net_mksocket(struct net_listener_s *nls) +{ + int value; + int ret; + + /* Create a listening socket */ + + message("net_listener: Initializing listener socket\n"); + nls->listensd = socket(AF_INET, SOCK_STREAM, 0); + if (nls->listensd < 0) + { + message("net_listener: socket failed: %d\n", errno); + return false; + } + + /* Configure the socket */ + + value = 1; + ret = setsockopt(nls->listensd, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(int)); + if (ret < 0) + { + message("net_listener: setsockopt failed: %d\n", errno); + close(nls->listensd); + return false; + } + + /* Set the socket to non-blocking */ + +#ifdef FIONBIO + ret = ioctl(nls->listensd, FIONBIO, (char *)&value); + if (ret < 0) + { + message("net_listener: ioctl failed: %d\n", errno); + close(nls->listensd); + return false; + } +#endif + + /* Bind the socket */ + + memset(&nls->addr, 0, sizeof(struct sockaddr_in)); + nls->addr.sin_family = AF_INET; + nls->addr.sin_addr.s_addr = htonl(INADDR_ANY); + nls->addr.sin_port = htons(LISTENER_PORT); + ret = bind(nls->listensd, (struct sockaddr *)&nls->addr, sizeof(struct sockaddr_in)); + if (ret < 0) + { + message("net_listener: bind failed: %d\n", errno); + close(nls->listensd); + return false; + } + + /* Mark the socket as a listener */ + + ret = listen(nls->listensd, 32); + if (ret < 0) + { + message("net_listener: bind failed: %d\n", errno); + close(nls->listensd); + return false; + } + + return true; +} + +/**************************************************************************** + * Name: net_configure + ****************************************************************************/ + +static void net_configure(void) +{ + struct in_addr addr; +#if defined(CONFIG_EXAMPLE_POLL_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif + + /* Configure uIP */ + /* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_POLL_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_POLL_IPADDR); + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_POLL_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_POLL_NETMASK); + uip_setnetmask("eth0", &addr); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: net_listener + ****************************************************************************/ + +void *net_listener(pthread_addr_t pvarg) +{ + struct net_listener_s nls; + struct timeval timeout; + int nsds; + int ret; + int i; + + /* Configure uIP */ + + net_configure(); + + /* Set up a listening socket */ + + memset(&nls, 0, sizeof(struct net_listener_s)); + if (!net_mksocket(&nls)) + { + return (void*)1; + } + + /* Initialize the 'master' file descriptor set */ + + FD_ZERO(&nls.master); + nls.mxsd = nls.listensd; + FD_SET(nls.listensd, &nls.master); + + /* Set up a 3 second timeout */ + + timeout.tv_sec = NET_LISTENER_DELAY; + timeout.tv_usec = 0; + + /* Loop waiting for incoming connections or for incoming data + * on any of the connect sockets. + */ + + for (;;) + { + /* Wait on select */ + + message("net_listener: Calling select(), listener sd=%d\n", nls.listensd); + memcpy(&nls.working, &nls.master, sizeof(fd_set)); + ret = select(nls.mxsd + 1, (FAR fd_set*)&nls.working, (FAR fd_set*)NULL, (FAR fd_set*)NULL, &timeout); + if (ret < 0) + { + message("net_listener: select failed: %d\n", errno); + break; + } + + /* Check for timeout */ + + if (ret == 0) + { + message("net_listener: Timeout\n"); + continue; + } + + /* Find which descriptors caused the wakeup */ + + nsds = ret; + for (i = 0; i <= nls.mxsd && nsds > 0; i++) + { + /* Is this descriptor ready? */ + + if (FD_ISSET(i, &nls.working)) + { + /* Yes, is it our listener? */ + + message("net_listener: Activity on sd=%d\n", i); + + nsds--; + if (i == nls.listensd) + { + (void)net_connection(&nls); + } + else + { + net_incomingdata(&nls, i); + } + } + } + } + + /* Cleanup */ + +#if 0 /* Don't get here */ + for (i = 0; i <= nls.mxsd; +i++) + { + if (FD_ISSET(i, &nls.master)) + { + close(i); + } + } +#endif + return NULL; /* Keeps some compilers from complaining */ +} diff --git a/apps/examples/poll/net_reader.c b/apps/examples/poll/net_reader.c new file mode 100644 index 000000000..b0cf94316 --- /dev/null +++ b/apps/examples/poll/net_reader.c @@ -0,0 +1,317 @@ +/**************************************************************************** + * examples/poll/net_reader.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/select.h> +#include <sys/socket.h> + +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include <net/if.h> +#include <apps/netutils/uiplib.h> + +#include "poll_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define IOBUFFER_SIZE 80 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: net_configure + ****************************************************************************/ + +static void net_configure(void) +{ + struct in_addr addr; +#if defined(CONFIG_EXAMPLE_POLL_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif + + /* Configure uIP */ + /* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_POLL_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_POLL_IPADDR); + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_POLL_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_POLL_NETMASK); + uip_setnetmask("eth0", &addr); +} + +/**************************************************************************** + * Name: net_receive + ****************************************************************************/ + +static void net_receive(int sd) +{ + struct timeval timeout; + char buffer[IOBUFFER_SIZE]; + char *ptr; + fd_set readset; + int nbytes; + int ret; + + /* Set up the timeout */ + + timeout.tv_sec = NET_LISTENER_DELAY; + timeout.tv_usec = 0; + + /* Loop while we have the connection */ + + for (;;) + { + /* Wait for incoming message */ + + do + { + FD_ZERO(&readset); + FD_SET(sd, &readset); + ret = select(sd + 1, (FAR fd_set*)&readset, (FAR fd_set*)NULL, (FAR fd_set*)NULL, &timeout); + } + while (ret < 0 && errno == EINTR); + + /* Something has happened */ + + if (ret < 0) + { + message("net_reader: select failed: %d\n", errno); + return; + } + else if (ret == 0) + { + message("net_reader: Timeout\n"); + } + else + { + message("net_reader: Read data from sd=%d\n", sd); + memset(buffer, '?', IOBUFFER_SIZE); /* Just to make sure we really receive something */ + ret = recv(sd, buffer, IOBUFFER_SIZE, 0); + if (ret < 0) + { + if (errno != EINTR) + { + message("net_reader: recv failed sd=%d: %d\n", sd, errno); + if (errno != EAGAIN) + { + return; + } + } + } + else if (ret == 0) + { + message("net_reader: Client connection lost sd=%d\n", sd); + return; + } + else + { + buffer[ret]='\0'; + message("net_reader: Read '%s' (%d bytes)\n", buffer, ret); + + /* Echo the data back to the client */ + + for (nbytes = ret, ptr = buffer; nbytes > 0; ) + { + ret = send(sd, ptr, nbytes, 0); + if (ret < 0) + { + if (errno != EINTR) + { + message("net_reader: Send failed sd=%d: %d\n", sd, errno); + return; + } + } + else + { + nbytes -= ret; + ptr += ret; + } + } + } + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: net_reader + ****************************************************************************/ + +void *net_reader(pthread_addr_t pvarg) +{ + struct sockaddr_in addr; +#ifdef POLL_HAVE_SOLINGER + struct linger ling; +#endif + int listensd; + int acceptsd; + socklen_t addrlen; + int optval; + + /* Configure uIP */ + + net_configure(); + + /* Create a new TCP socket */ + + listensd = socket(PF_INET, SOCK_STREAM, 0); + if (listensd < 0) + { + message("net_reader: socket failure: %d\n", errno); + goto errout; + } + + /* Set socket to reuse address */ + + optval = 1; + if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0) + { + message("net_reader: setsockopt SO_REUSEADDR failure: %d\n", errno); + goto errout_with_listensd; + } + + /* Bind the socket to a local address */ + + addr.sin_family = AF_INET; + addr.sin_port = HTONS(LISTENER_PORT); + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(listensd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) + { + message("net_reader: bind failure: %d\n", errno); + goto errout_with_listensd; + } + + /* Listen for connections on the bound TCP socket */ + + if (listen(listensd, 5) < 0) + { + message("net_reader: listen failure %d\n", errno); + goto errout_with_listensd; + } + + /* Connection loop */ + + for (;;) + { + /* Accept only one connection */ + + message("net_reader: Accepting new connections on port %d\n", LISTENER_PORT); + addrlen = sizeof(struct sockaddr_in); + acceptsd = accept(listensd, (struct sockaddr*)&addr, &addrlen); + if (acceptsd < 0) + { + message("net_reader: accept failure: %d\n", errno); + continue; + } + message("net_reader: Connection accepted on sd=%d\n", acceptsd); + + /* Configure to "linger" until all data is sent when the socket is closed */ + +#ifdef POLL_HAVE_SOLINGER + ling.l_onoff = 1; + ling.l_linger = 30; /* timeout is seconds */ + if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0) + { + message("net_reader: setsockopt SO_LINGER failure: %d\n", errno); + goto errout_with_acceptsd; + } +#endif + + /* Handle incoming messsages on the connection. */ + + net_receive(acceptsd); + + message("net_reader: Closing sd=%d\n", acceptsd); + close(acceptsd); + } + +#ifdef POLL_HAVE_SOLINGER +errout_with_acceptsd: + close(acceptsd); +#endif +errout_with_listensd: + close(listensd); +errout: + return NULL; +} diff --git a/apps/examples/poll/poll_internal.h b/apps/examples/poll/poll_internal.h new file mode 100644 index 000000000..cbf42ac56 --- /dev/null +++ b/apps/examples/poll/poll_internal.h @@ -0,0 +1,128 @@ +/**************************************************************************** + * examples/poll/poll_internal.h + * + * Copyright (C) 2008, 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_PIPE_PIPE_H +#define __EXAMPLES_PIPE_PIPE_H + +/**************************************************************************** + * Compilation Switches + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <pthread.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifdef CONFIG_DISABLE_POLL +# error "The polling API is disabled" +#endif + +/* Here are all of the configuration settings that must be met to have TCP/IP + * poll/select support. This kind of looks like overkill. + * + * CONFIG_NET - Network support must be enabled + * CONFIG_NSOCKET_DESCRIPTORS - Socket descriptors must be allocated + * CONFIG_NET_TCP - Only support on TCP (because read-ahead + * ibuffering s not yet support for UDP) + * CONFIG_NET_NTCP_READAHEAD_BUFFERS - TCP/IP read-ahead buffering must be enabled + */ + +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \ + defined(CONFIG_NET_TCP) && CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 +# define HAVE_NETPOLL 1 +#else +# undef HAVE_NETPOLL +#endif + +/* If debug is enabled, then use lib_rawprintf so that OS debug output and + * the test output are synchronized. + * + * These macros will differ depending upon if the toolchain supports + * macros with a variable number of arguments or not. + */ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_rawprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_rawprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +#define FIFO_PATH1 "/dev/fifo0" +#define FIFO_PATH2 "/dev/fifo1" + +#define POLL_LISTENER_DELAY 2000 /* 2 seconds */ +#define SELECT_LISTENER_DELAY 4 /* 4 seconds */ +#define NET_LISTENER_DELAY 3 /* 3 seconds */ +#define WRITER_DELAY 6 /* 6 seconds */ + +#define LISTENER_PORT 5471 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +extern void *poll_listener(pthread_addr_t pvarg); +extern void *select_listener(pthread_addr_t pvarg); + +#ifdef HAVE_NETPOLL +extern void *net_listener(pthread_addr_t pvarg); +extern void *net_reader(pthread_addr_t pvarg); +#endif +#endif /* __EXAMPLES_PIPE_PIPE_H */ diff --git a/apps/examples/poll/poll_listener.c b/apps/examples/poll/poll_listener.c new file mode 100644 index 000000000..816647e34 --- /dev/null +++ b/apps/examples/poll/poll_listener.c @@ -0,0 +1,262 @@ +/**************************************************************************** + * examples/poll/poll_listener.c + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <poll.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include "poll_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#if defined(CONFIG_DEV_CONSOLE) && !defined(CONFIG_DEV_LOWCONSOLE) +# define HAVE_CONSOLE +# define NPOLLFDS 2 +# define CONSNDX 0 +# define FIFONDX 1 +#else +# undef HAVE_CONSOLE +# define NPOLLFDS 1 +# define FIFONDX 0 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: poll_listener + ****************************************************************************/ + +void *poll_listener(pthread_addr_t pvarg) +{ + struct pollfd fds[NPOLLFDS]; + char buffer[64]; + ssize_t nbytes; + bool timeout; + bool pollin; + int nevents; + int fd; + int ret; + int i; + + /* Open the FIFO for non-blocking read */ + + message("poll_listener: Opening %s for non-blocking read\n", FIFO_PATH1); + fd = open(FIFO_PATH1, O_RDONLY|O_NONBLOCK); + if (fd < 0) + { + message("poll_listener: ERROR Failed to open FIFO %s: %d\n", + FIFO_PATH1, errno); + (void)close(fd); + return (void*)-1; + } + + /* Loop forever */ + + for (;;) + { + message("poll_listener: Calling poll()\n"); + + memset(fds, 0, sizeof(struct pollfd)*NPOLLFDS); +#ifdef HAVE_CONSOLE + fds[CONSNDX].fd = 0; + fds[CONSNDX].events = POLLIN; + fds[CONSNDX].revents = 0; +#endif + fds[FIFONDX].fd = fd; + fds[FIFONDX].events = POLLIN; + fds[FIFONDX].revents = 0; + + timeout = false; + pollin = false; + + ret = poll(fds, NPOLLFDS, POLL_LISTENER_DELAY); + + message("\npoll_listener: poll returned: %d\n", ret); + if (ret < 0) + { + message("poll_listener: ERROR poll failed: %d\n", errno); + } + else if (ret == 0) + { + message("poll_listener: Timeout\n"); + timeout = true; + } + else if (ret > NPOLLFDS) + { + message("poll_listener: ERROR poll reported: %d\n"); + } + else + { + pollin = true; + } + + nevents = 0; + for (i = 0; i < NPOLLFDS; i++) + { + message("poll_listener: FIFO revents[%d]=%02x\n", i, fds[i].revents); + if (timeout) + { + if (fds[i].revents != 0) + { + message("poll_listener: ERROR? expected revents=00, received revents[%d]=%02x\n", + fds[i].revents, i); + } + } + else if (pollin) + { + if (fds[i].revents == POLLIN) + { + nevents++; + } + else if (fds[i].revents != 0) + { + message("poll_listener: ERROR unexpected revents[i]=%02x\n", + i, fds[i].revents); + } + } + } + + if (pollin && nevents != ret) + { + message("poll_listener: ERROR found %d events, poll reported %d\n", nevents, ret); + } + + /* In any event, read until the pipe/serial is empty */ + + for (i = 0; i < NPOLLFDS; i++) + { + do + { +#ifdef HAVE_CONSOLE + /* Hack to work around the fact that the console driver on the + * simulator is always non-blocking. + */ + + if (i == CONSNDX) + { + if ((fds[CONSNDX].revents & POLLIN) != 0) + { + buffer[0] = getchar(); + nbytes = 1; + } + else + { + nbytes = 0; + } + } + else +#endif + { + /* The pipe works differently, it returns whatever data + * it has available without blocking. + */ + + nbytes = read(fds[i].fd, buffer, 63); + } + + if (nbytes <= 0) + { + if (nbytes == 0 || errno == EAGAIN) + { + if ((fds[i].revents & POLLIN) != 0) + { + message("poll_listener: ERROR no read data[%d]\n", i); + } + } + else if (errno != EINTR) + { + message("poll_listener: read[%d] failed: %d\n", i, errno); + } + nbytes = 0; + } + else + { + if (timeout) + { + message("poll_listener: ERROR? Poll timeout, but data read[%d]\n", i); + message(" (might just be a race condition)\n"); + } + + buffer[nbytes] = '\0'; + message("poll_listener: Read[%d] '%s' (%d bytes)\n", i, buffer, nbytes); + } + + /* Suppress error report if no read data on the next time through */ + + fds[i].revents = 0; + } + while (nbytes > 0); + } + + /* Make sure that everything is displayed */ + + msgflush(); + } + + /* Won't get here */ + + (void)close(fd); + return NULL; +} diff --git a/apps/examples/poll/poll_main.c b/apps/examples/poll/poll_main.c new file mode 100644 index 000000000..3db0150e7 --- /dev/null +++ b/apps/examples/poll/poll_main.c @@ -0,0 +1,221 @@ +/**************************************************************************** + * examples/poll/poll_main.c + * + * Copyright (C) 2008, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <poll.h> +#include <errno.h> +#include <debug.h> + +#include "poll_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + char buffer[64]; + ssize_t nbytes; + pthread_t tid1; + pthread_t tid2; +#ifdef HAVE_NETPOLL + pthread_t tid3; +#endif + int count; + int fd1 = -1; + int fd2 = -1; + int ret; + int exitcode = 0; + + /* Open FIFOs */ + + message("\nuser_start: Creating FIFO %s\n", FIFO_PATH1); + ret = mkfifo(FIFO_PATH1, 0666); + if (ret < 0) + { + message("user_start: mkfifo failed: %d\n", errno); + exitcode = 1; + goto errout; + } + + message("\nuser_start: Creating FIFO %s\n", FIFO_PATH2); + ret = mkfifo(FIFO_PATH2, 0666); + if (ret < 0) + { + message("user_start: mkfifo failed: %d\n", errno); + exitcode = 2; + goto errout; + } + + /* Open the FIFOs for blocking, write */ + + fd1 = open(FIFO_PATH1, O_WRONLY); + if (fd1 < 0) + { + message("user_start: Failed to open FIFO %s for writing, errno=%d\n", + FIFO_PATH1, errno); + exitcode = 3; + goto errout; + } + + fd2 = open(FIFO_PATH2, O_WRONLY); + if (fd2 < 0) + { + message("user_start: Failed to open FIFO %s for writing, errno=%d\n", + FIFO_PATH2, errno); + exitcode = 4; + goto errout; + } + + /* Start the listeners */ + + message("user_start: Starting poll_listener thread\n"); + + ret = pthread_create(&tid1, NULL, poll_listener, NULL); + if (ret != 0) + { + message("user_start: Failed to create poll_listener thread: %d\n", ret); + exitcode = 5; + goto errout; + } + + message("user_start: Starting select_listener thread\n"); + + ret = pthread_create(&tid2, NULL, select_listener, NULL); + if (ret != 0) + { + message("user_start: Failed to create select_listener thread: %d\n", ret); + exitcode = 6; + goto errout; + } + +#ifdef HAVE_NETPOLL +#ifdef CONFIG_NET_TCPBACKLOG + message("user_start: Starting net_listener thread\n"); + + ret = pthread_create(&tid3, NULL, net_listener, NULL); +#else + message("user_start: Starting net_reader thread\n"); + + ret = pthread_create(&tid3, NULL, net_reader, NULL); +#endif + if (ret != 0) + { + message("user_start: Failed to create net_listener thread: %d\n", ret); + } +#endif + + /* Loop forever */ + + for (count = 0; ; count++) + { + /* Send a message to the listener... this should wake the listener + * from the poll. + */ + + sprintf(buffer, "Message %d", count); + nbytes = write(fd1, buffer, strlen(buffer)); + if (nbytes < 0) + { + message("user_start: Write to fd1 failed: %d\n", errno); + exitcode = 7; + goto errout; + } + + nbytes = write(fd2, buffer, strlen(buffer)); + if (nbytes < 0) + { + message("user_start: Write fd2 failed: %d\n", errno); + exitcode = 8; + goto errout; + } + + message("\nuser_start: Sent '%s' (%d bytes)\n", buffer, nbytes); + msgflush(); + + /* Wait awhile. This delay should be long enough that the + * listener will timeout. + */ + + sleep(WRITER_DELAY); + } + +errout: + if (fd1 >= 0) + { + close(fd1); + } + + if (fd2 >= 0) + { + close(fd2); + } + + fflush(stdout); + return exitcode; +} diff --git a/apps/examples/poll/select_listener.c b/apps/examples/poll/select_listener.c new file mode 100644 index 000000000..80039ada3 --- /dev/null +++ b/apps/examples/poll/select_listener.c @@ -0,0 +1,193 @@ +/**************************************************************************** + * examples/poll/select_listener.c + * + * Copyright (C) 2008, 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/select.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include "poll_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: select_listener + ****************************************************************************/ + +void *select_listener(pthread_addr_t pvarg) +{ + fd_set rfds; + struct timeval tv; + char buffer[64]; + ssize_t nbytes; + bool timeout; + bool ready; + int fd; + int ret; + + /* Open the FIFO for non-blocking read */ + + message("select_listener: Opening %s for non-blocking read\n", FIFO_PATH2); + fd = open(FIFO_PATH2, O_RDONLY|O_NONBLOCK); + if (fd < 0) + { + message("select_listener: ERROR Failed to open FIFO %s: %d\n", + FIFO_PATH2, errno); + (void)close(fd); + return (void*)-1; + } + + /* Loop forever */ + + for (;;) + { + message("select_listener: Calling select()\n"); + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + tv.tv_sec = SELECT_LISTENER_DELAY; + tv.tv_usec = 0; + + timeout = false; + ready = false; + + ret = select(fd+1, (FAR fd_set*)&rfds, (FAR fd_set*)NULL, (FAR fd_set*)NULL, &tv); + message("\nselect_listener: select returned: %d\n", ret); + + if (ret < 0) + { + message("select_listener: ERROR select failed: %d\n"); + } + else if (ret == 0) + { + message("select_listener: Timeout\n"); + timeout = true; + } + else + { + if (ret != 1) + { + message("select_listener: ERROR poll reported: %d\n"); + } + else + { + ready = true; + } + + if (!FD_ISSET(fd, rfds)) + { + message("select_listener: ERROR fd=%d not in fd_set\n"); + } + } + + /* In any event, read until the pipe is empty */ + + do + { + nbytes = read(fd, buffer, 63); + if (nbytes <= 0) + { + if (nbytes == 0 || errno == EAGAIN) + { + if (ready) + { + message("select_listener: ERROR no read data\n"); + } + } + else if (errno != EINTR) + { + message("select_listener: read failed: %d\n", errno); + } + nbytes = 0; + } + else + { + if (timeout) + { + message("select_listener: ERROR? Poll timeout, but data read\n"); + message(" (might just be a race condition)\n"); + } + + buffer[nbytes] = '\0'; + message("select_listener: Read '%s' (%d bytes)\n", buffer, nbytes); + } + + timeout = false; + ready = false; + } + while (nbytes > 0); + + /* Make sure that everything is displayed */ + + msgflush(); + } + + /* Won't get here */ + + (void)close(fd); + return NULL; +} diff --git a/apps/examples/rgmp/Makefile b/apps/examples/rgmp/Makefile new file mode 100644 index 000000000..cefe63d54 --- /dev/null +++ b/apps/examples/rgmp/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# examples/rgmp/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# The smallest thing you can build -- the NULL example. + +ASRCS = +CSRCS = main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/rgmp/main.c b/apps/examples/rgmp/main.c new file mode 100644 index 000000000..ec6450c50 --- /dev/null +++ b/apps/examples/rgmp/main.c @@ -0,0 +1,66 @@ +/**************************************************************************** + * examples/rgmp/main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdio.h> +#include <string.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + // TODO: add your code here + + return 0; +} + diff --git a/apps/examples/romfs/Makefile b/apps/examples/romfs/Makefile new file mode 100644 index 000000000..1db45765a --- /dev/null +++ b/apps/examples/romfs/Makefile @@ -0,0 +1,111 @@ +############################################################################ +# apps/examples/romfs/Makefile +# +# Copyright (C) 2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# ROMFS File System Example + +ASRCS = +CSRCS = romfs_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: checkgenromfs clean depend disclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +checkgenromfs: + @genromfs -h 1>/dev/null 2>&1 || { \ + echo "Host executable genromfs not available in PATH"; \ + echo "You may need to download in from http://romfs.sourceforge.net/"; \ + exit 1; \ + } + +testdir : testdir.tar.gz + @tar zxf $< || { echo "tar zxf $< failed" ; exit 1 ; } + +testdir.img : checkgenromfs testdir + @genromfs -f $@ -d testdir -V "ROMFS_Test" || { echo "genromfs failed" ; exit 1 ; } + +romfs_testdir.h : testdir.img + @xxd -i $< >$@ || { echo "xxd of $< failed" ; exit 1 ; } + +.built: romfs_testdir.h $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +# Register application +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend testdir.img + +-include Make.dep + diff --git a/apps/examples/romfs/romfs_main.c b/apps/examples/romfs/romfs_main.c new file mode 100644 index 000000000..32b3d2654 --- /dev/null +++ b/apps/examples/romfs/romfs_main.c @@ -0,0 +1,498 @@ +/**************************************************************************** + * examples/romfs/romfs_main.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* Mount the ROMFS image, Verifty that it contains the + * following: + * + * testdir + * |---------- [drwxr-xr-x 4096] adir + * | |------ [-rw-r--r-- 21] anotherfile.txt + * | |------ [drwxr-xr-x 4096] subdir + * | | `-- [-rw-r--r-- 21] subdirfile.txt + * | `------ [-rw-r--r-- 25] yafile.txt + * |---------- [-rw-r--r-- 15] afile.txt + * |---------- [-rw-r--r-- 21] hfile + * `---------- [lrwxrwxrwx 11] ldir -> adir/subdir + * + * testdir/ldir is a soft-link and should not be detectable. + * hfile is a hardlink to subdirfile and should be identical + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> + +#include <nuttx/ramdisk.h> + +#include "romfs_testdir.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Configuration settings */ + +#ifndef CONFIG_EXAMPLES_ROMFS_RAMDEVNO +# define CONFIG_EXAMPLES_ROMFS_RAMDEVNO 1 +#endif + +#ifndef CONFIG_EXAMPLES_ROMFS_SECTORSIZE +# define CONFIG_EXAMPLES_ROMFS_SECTORSIZE 64 +#endif + +#ifndef CONFIG_EXAMPLES_ROMFS_MOUNTPOINT +# define CONFIG_EXAMPLES_ROMFS_MOUNTPOINT "/usr/local/share" +#endif + +#ifdef CONFIG_DISABLE_MOUNTPOINT +# error "Mountpoint support is disabled" +#endif + +#if CONFIG_NFILE_DESCRIPTORS < 4 +# error "Not enough file descriptors" +#endif + +#ifndef CONFIG_FS_ROMFS +# error "ROMFS support not enabled" +#endif + +#define NSECTORS(b) (((b)+CONFIG_EXAMPLES_ROMFS_SECTORSIZE-1)/CONFIG_EXAMPLES_ROMFS_SECTORSIZE) +#define STR_RAMDEVNO(m) #m +#define MKMOUNT_DEVNAME(m) "/dev/ram" STR_RAMDEVNO(m) +#define MOUNT_DEVNAME MKMOUNT_DEVNAME(CONFIG_EXAMPLES_ROMFS_RAMDEVNO) + +#define SCRATCHBUFFER_SIZE 1024 + +/* Test directory stuff */ + +#define WRITABLE_MODE (S_IWOTH|S_IWGRP|S_IWUSR) +#define READABLE_MODE (S_IROTH|S_IRGRP|S_IRUSR) +#define EXECUTABLE_MODE (S_IXOTH|S_IXGRP|S_IXUSR) + +#define DIRECTORY_MODE (S_IFDIR|READABLE_MODE|EXECUTABLE_MODE) +#define FILE_MODE (S_IFREG|READABLE_MODE) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct node_s +{ + struct node_s *peer; /* Next node in this directory */ + bool directory; /* True: directory */ + bool found; /* True: found and verified */ + const char *name; /* Node name */ + mode_t mode; /* Expected permissions */ + size_t size; /* Expected size */ + union + { + const char *filecontent; /* Context of text file */ + struct node_s *child; /* Subdirectory start */ + } u; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_afilecontent[] = "This is a file\n"; +static const char g_anotherfilecontent[] = "This is another file\n"; +static const char g_yafilecontent[] = "This is yet another file\n"; +static const char g_subdirfilecontent[] = "File in subdirectory\n"; + +#define g_hfilecontent g_subdirfilecontent + +static struct node_s g_adir; +static struct node_s g_afile; +static struct node_s g_hfile; + +static struct node_s g_anotherfile; +static struct node_s g_subdir; +static struct node_s g_yafile; + +static struct node_s g_subdirfile; + +static int g_nerrors = 0; + +static char g_scratchbuffer[SCRATCHBUFFER_SIZE]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: + ****************************************************************************/ + +static void connectem(void) +{ + g_adir.peer = &g_afile; + g_adir.directory = true; + g_adir.found = false; + g_adir.name = "adir"; + g_adir.mode = DIRECTORY_MODE; + g_adir.size = 0; + g_adir.u.child = &g_anotherfile; + + g_afile.peer = &g_hfile; + g_afile.directory = false; + g_afile.found = false; + g_afile.name = "afile.txt"; + g_afile.mode = FILE_MODE; + g_afile.size = strlen(g_afilecontent); + g_afile.u.filecontent = g_afilecontent; + + g_hfile.peer = NULL; + g_hfile.directory = false; /* Actually a hard link */ + g_hfile.found = false; + g_hfile.name = "hfile"; + g_hfile.mode = FILE_MODE; + g_hfile.size = strlen(g_hfilecontent); + g_hfile.u.filecontent = g_hfilecontent; + + g_anotherfile.peer = &g_yafile; + g_anotherfile.directory = false; + g_anotherfile.found = false; + g_anotherfile.name = "anotherfile.txt"; + g_anotherfile.mode = FILE_MODE; + g_anotherfile.size = strlen(g_anotherfilecontent); + g_anotherfile.u.filecontent = g_anotherfilecontent; + + g_yafile.peer = &g_subdir; + g_yafile.directory = false; + g_yafile.found = false; + g_yafile.name = "yafile.txt"; + g_yafile.mode = FILE_MODE; + g_yafile.size = strlen(g_yafilecontent); + g_yafile.u.filecontent = g_yafilecontent; + + g_subdir.peer = NULL; + g_subdir.directory = true; + g_subdir.found = false; + g_subdir.name = "subdir"; + g_subdir.mode = DIRECTORY_MODE; + g_subdir.size = 0; + g_subdir.u.child = &g_subdirfile; + + g_subdirfile.peer = NULL; + g_subdirfile.directory = false; + g_subdirfile.found = false; + g_subdirfile.name = "subdirfile.txt"; + g_subdirfile.mode = FILE_MODE; + g_subdirfile.size = strlen(g_subdirfilecontent); + g_subdirfile.u.filecontent = g_subdirfilecontent; +} + +/**************************************************************************** + * Name: findindirectory + ****************************************************************************/ + +static struct node_s *findindirectory(struct node_s *entry, const char *name) +{ + for (; entry; entry = entry->peer) + { + if (!entry->found && strcmp(entry->name, name) == 0) + { + entry->found = true; + return entry; + } + } + return NULL; +} + +/**************************************************************************** + * Name: checkattributes + ****************************************************************************/ + +static void checkattributes(const char *path, mode_t mode, size_t size) +{ + struct stat buf; + int ret; + + ret = stat(path, &buf); + if (ret != 0) + { + printf(" -- ERROR: Failed to stat %s: %d\n", path, errno); + g_nerrors++; + return; + } + + if (mode != buf.st_mode) + { + printf(" -- ERROR: Expected mode %08x, got %08x\n", mode, buf.st_mode); + g_nerrors++; + } + + if (size != buf.st_size) + { + printf(" -- ERROR: Expected size %d, got %d\n", mode, buf.st_size); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: checkfile + ****************************************************************************/ + +static void checkfile(const char *path, struct node_s *node) +{ + ssize_t nbytesread; + char *filedata; + int fd; + + /* Open the file */ + + fd = open(path, O_RDONLY); + if (fd < 0) + { + printf(" -- ERROR: Failed to open %s: %d\n", path, errno); + g_nerrors++; + return; + } + + /* Read and verify the file contents */ + + nbytesread = read(fd, g_scratchbuffer, SCRATCHBUFFER_SIZE); + if (nbytesread < 0) + { + printf(" -- ERROR: Failed to read from %s: %d\n", path, errno); + g_nerrors++; + } + else if (nbytesread != node->size) + { + printf(" -- ERROR: Read %d bytes, expected %d\n", nbytesread, node->size); + g_nerrors++; + } + else if (memcmp(g_scratchbuffer, node->u.filecontent, node->size) != 0) + { + g_scratchbuffer[nbytesread] = '\0'; + printf(" -- ERROR: File content read does not match expectation:\n"); + printf(" -- Read: [%s]\n", g_scratchbuffer); + printf(" -- Expected: [%s]\n", node->u.filecontent); + g_nerrors++; + } + + /* Memory map and verify the file contents */ + + filedata = (char*)mmap(NULL, node->size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0); + if (!filedata || filedata == (char*)MAP_FAILED) + { + printf(" -- ERROR: mmap of %s failed: %d\n", path, errno); + g_nerrors++; + } + else + { + if (memcmp(filedata, node->u.filecontent, node->size) != 0) + { + memcpy(g_scratchbuffer, filedata, node->size); + g_scratchbuffer[node->size] = '\0'; + printf(" -- ERROR: Mapped file content read does not match expectation:\n"); + printf(" -- Memory: [%s]\n", filedata); + printf(" -- Expected: [%s]\n", node->u.filecontent); + g_nerrors++; + } + munmap(filedata, node->size); + } + + /* Close the file */ + + if (close(fd) != OK) + { + printf(" -- ERROR: Failed to close %s: %d\n", path, errno); + g_nerrors++; + } +} + +/**************************************************************************** + * Name: readdirectories + ****************************************************************************/ + +static void readdirectories(const char *path, struct node_s *entry) +{ + DIR *dirp; + struct node_s *node; + struct dirent *direntry; + char *fullpath; + + printf("Traversing directory: %s\n", path); + dirp = opendir(path); + if (!dirp) + { + printf(" ERROR opendir(\"%s\") failed: %d\n", path, errno); + g_nerrors++; + return; + } + + for (direntry = readdir(dirp); direntry; direntry = readdir(dirp)) + { + if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) + { + printf(" Skipping %s\n", direntry->d_name); + continue; + } + + node = findindirectory(entry, direntry->d_name); + if (!node) + { + printf(" ERROR: No node found for %s\n", direntry->d_name); + g_nerrors++; + continue; + } + + /* Get the full path to the entry */ + + sprintf(g_scratchbuffer, "%s/%s", path, direntry->d_name); + fullpath = strdup(g_scratchbuffer); + + if (DIRENT_ISDIRECTORY(direntry->d_type)) + { + printf(" DIRECTORY: %s/\n", fullpath); + if (!node->directory) + { + printf(" -- ERROR: Expected type directory\n"); + g_nerrors++; + } + else + { + checkattributes(fullpath, node->mode, 0); + readdirectories(fullpath, node->u.child); + printf("Continuing directory: %s\n", path); + } + } + else + { + printf(" FILE: %s/\n", fullpath); + if (node->directory) + { + printf(" -- ERROR: Expected type file\n"); + g_nerrors++; + } + else + { + checkattributes(fullpath, node->mode, node->size); + checkfile(fullpath, node); + } + } + free(fullpath); + } + + closedir(dirp); +} + +/**************************************************************************** + * Name: checkdirectories + ****************************************************************************/ + +static void checkdirectories(struct node_s *entry) +{ + for (; entry; entry = entry->peer) + { + if (!entry->found ) + { + printf("ERROR: %s never found\n", entry->name); + g_nerrors++; + } + + if (entry->directory) + { + checkdirectories(entry->u.child); + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + int ret; + + /* Create a RAM disk for the test */ + + ret = romdisk_register(CONFIG_EXAMPLES_ROMFS_RAMDEVNO, testdir_img, + NSECTORS(testdir_img_len), CONFIG_EXAMPLES_ROMFS_SECTORSIZE); + if (ret < 0) + { + printf("ERROR: Failed to create RAM disk\n"); + return 1; + } + + /* Mount the test file system */ + + printf("Mounting ROMFS filesystem at target=%s with source=%s\n", + CONFIG_EXAMPLES_ROMFS_MOUNTPOINT, MOUNT_DEVNAME); + + ret = mount(MOUNT_DEVNAME, CONFIG_EXAMPLES_ROMFS_MOUNTPOINT, "romfs", MS_RDONLY, NULL); + if (ret < 0) + { + printf("ERROR: Mount failed: %d\n", errno); + return 1; + } + + /* Perform the test */ + + connectem(); + readdirectories(CONFIG_EXAMPLES_ROMFS_MOUNTPOINT, &g_adir); + checkdirectories(&g_adir); + + if (g_nerrors) + { + printf("Finished with %d errors\n", g_nerrors); + return g_nerrors; + } + + printf("PASSED\n"); + return 0; +} diff --git a/apps/examples/romfs/romfs_testdir.h b/apps/examples/romfs/romfs_testdir.h new file mode 100644 index 000000000..53f93105c --- /dev/null +++ b/apps/examples/romfs/romfs_testdir.h @@ -0,0 +1,89 @@ +unsigned char testdir_img[] = { + 0x2d, 0x72, 0x6f, 0x6d, 0x31, 0x66, 0x73, 0x2d, 0x00, 0x00, 0x02, 0x60, + 0x27, 0x43, 0x4a, 0x8a, 0x52, 0x4f, 0x4d, 0x46, 0x53, 0x5f, 0x54, 0x65, + 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xff, 0x97, + 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xff, 0x80, 0x2e, 0x2e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, + 0x93, 0x9b, 0x95, 0xf0, 0x6c, 0x64, 0x69, 0x72, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x64, 0x69, 0x72, + 0x2f, 0x73, 0x75, 0x62, 0x64, 0x69, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x19, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, + 0x9e, 0x9b, 0x93, 0xc5, 0x61, 0x64, 0x69, 0x72, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x58, 0x47, 0x43, 0xf1, + 0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x66, 0x69, 0x6c, 0x65, 0x2e, + 0x74, 0x78, 0x74, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6c, 0x65, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, + 0xa1, 0xc5, 0x69, 0xd8, 0x79, 0x61, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x74, + 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, + 0x20, 0x69, 0x73, 0x20, 0x79, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x6f, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x90, + 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xfe, 0x20, 0x2e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x70, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0xd1, 0xd1, 0xfe, 0x70, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x23, 0x18, 0x9c, 0x03, + 0x73, 0x75, 0x62, 0x64, 0x69, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x15, 0x3e, 0x3f, 0x06, 0xd8, 0x73, 0x75, 0x62, 0x64, + 0x69, 0x72, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x00, + 0x46, 0x69, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x75, 0x62, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, + 0x00, 0x00, 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xfc, 0xa0, + 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, + 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xff, 0x70, 0x2e, 0x2e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x99, 0x92, 0xd4, 0x68, 0x66, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc5, 0x6b, 0x22, 0x0b, + 0x61, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +unsigned int testdir_img_len = 1024; diff --git a/apps/examples/romfs/testdir.tar.gz b/apps/examples/romfs/testdir.tar.gz Binary files differnew file mode 100644 index 000000000..cd0e9c518 --- /dev/null +++ b/apps/examples/romfs/testdir.tar.gz diff --git a/apps/examples/romfs/testdir.txt b/apps/examples/romfs/testdir.txt new file mode 100644 index 000000000..e321d6ded --- /dev/null +++ b/apps/examples/romfs/testdir.txt @@ -0,0 +1,105 @@ +VOLUME HEADER: Name=ROMFS_Test +0000000: 2d72 6f6d 3166 732d 0000 0260 2743 4a8a -rom1fs-...`'CJ. +0000010: 524f 4d46 535f 5465 7374 0000 0000 0000 ROMFS_Test...... + +FILE HEADER 1: Name=. +0000020: 0000 0049 0000 0020 0000 0000 d1ff ff97 ...I... ........ +0000030: 2e00 0000 0000 0000 0000 0000 0000 0000 ................ + +FILE HEADER 2: Name=.. +0000040: 0000 0060 0000 0020 0000 0000 d1d1 ff80 ...`... ........ +0000050: 2e2e 0000 0000 0000 0000 0000 0000 0000 ................ + +FILE HEADER 3: Name=ldir +0000060: 0000 0093 0000 0000 0000 000b 939b 95f0 ................ +0000070: 6c64 6972 0000 0000 0000 0000 0000 0000 ldir............ + + FILE CONTENT: + 0000080: 6164 6972 2f73 7562 6469 7200 0000 0000 adir/subdir..... + +FILE HEADER 4: Name=adir +0000090: 0000 0219 0000 00b0 0000 0000 9e9b 93c5 ................ +00000a0: 6164 6972 0000 0000 0000 0000 0000 0000 adir............ + + FILE HEADER 4.1: Name=anotherfile.txt + 00000b0: 0000 00f2 0000 0000 0000 0015 5847 43f1 ............XGC. + 00000c0: 616e 6f74 6865 7266 696c 652e 7478 7400 anotherfile.txt. + + FILE CONTENT: + 00000d0: 5468 6973 2069 7320 616e 6f74 6865 7220 This is another + 00000e0: 6669 6c65 0a00 0000 0000 0000 0000 0000 file............ + + FILE HEADER 4.2: Name=yafile.txt + 00000f0: 0000 0132 0000 0000 0000 0019 a1c5 69d8 ...2..........i. + 0000100: 7961 6669 6c65 2e74 7874 0000 0000 0000 yafile.txt...... + + FILE CONTENT: + 0000110: 5468 6973 2069 7320 7965 7420 616e 6f74 This is yet anot + 0000120: 6865 7220 6669 6c65 0a00 0000 0000 0000 her file........ + + FILE HEADER 4.3: Name=. + 0000130: 0000 0150 0000 0090 0000 0000 d1ff fe20 ...P........... + 0000140: 2e00 0000 0000 0000 0000 0000 0000 0000 ................ + + FILE HEADER 4.4: Name=.. + 0000150: 0000 0170 0000 0020 0000 0000 d1d1 fe70 ...p... .......p + 0000160: 2e2e 0000 0000 0000 0000 0000 0000 0000 ................ + + FILE HEADER 4.5: Name=subdir + 0000170: 0000 0009 0000 0190 0000 0000 2318 9c03 ............#... + 0000180: 7375 6264 6972 0000 0000 0000 0000 0000 subdir.......... + + FILE HEADER 4.5.1: Name=subdirfile.txt + 0000190: 0000 01d2 0000 0000 0000 0015 3e3f 06d8 ............>?.. + 00001a0: 7375 6264 6972 6669 6c65 2e74 7874 0000 subdirfile.txt.. + + FILE CONTENT: + 00001b0: 4669 6c65 2069 6e20 7375 6264 6972 6563 File in subdirec + 00001c0: 746f 7279 0a00 0000 0000 0000 0000 0000 tory............ + + FILE HEADER 4.5.2: Name=. + 00001d0: 0000 01f0 0000 0170 0000 0000 d1ff fca0 .......p........ + 00001e0: 2e00 0000 0000 0000 0000 0000 0000 0000 ................ + + FILE HEADER 4.5.3: Name=.. + 00001f0: 0000 0000 0000 0090 0000 0000 d1d1 ff70 ...............p + 0000200: 2e2e 0000 0000 0000 0000 0000 0000 0000 ................ + +FILE HEADER 5: Name=hfile +0000210: 0000 0230 0000 0190 0000 0000 3299 92d4 ...0........2... +0000220: 6866 696c 6500 0000 0000 0000 0000 0000 hfile........... + +FILE HEADER 6: Name=afile.txt +0000230: 0000 0002 0000 0000 0000 000f c56b 220b .............k". +0000240: 6166 696c 652e 7478 7400 0000 0000 0000 afile.txt....... + + FILE CONTENT: + 0000250: 5468 6973 2069 7320 6120 6669 6c65 0a00 This is a file.. + +PADDING +0000260: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000270: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000280: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000290: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00002a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00002b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00002c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00002d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00002e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00002f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000300: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000310: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000320: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000330: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000340: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000350: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000360: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000370: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000380: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +0000390: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00003a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00003b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00003c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00003d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00003e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ +00003f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ diff --git a/apps/examples/sendmail/Makefile b/apps/examples/sendmail/Makefile new file mode 100644 index 000000000..2c8883c28 --- /dev/null +++ b/apps/examples/sendmail/Makefile @@ -0,0 +1,96 @@ +############################################################################ +# apps/examples/sendmail/Makefile +# +# Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Sendmail SMTP Example + +ASRCS = +CSRCS = target.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +# Register application +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + @$(MAKE) -f Makefile.host clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/sendmail/Makefile.host b/apps/examples/sendmail/Makefile.host new file mode 100644 index 000000000..3b99432e3 --- /dev/null +++ b/apps/examples/sendmail/Makefile.host @@ -0,0 +1,77 @@ +############################################################################ +# apps/examples/sendmail/Makefile.host +# +# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TOPDIR must be defined on the make command line + +-include $(TOPDIR)/Make.defs + +OBJS = host.o1 smtp.o1 +BIN = sendmail + +HOSTCFLAGS += -DCONFIG_WEBCLIENT_HOST=1 +HOSTCFLAGS += -I. -include hostdefs.h -Iinclude +VPATH = $(TOPDIR)/netutils/smtp:. + +all: $(BIN) +.PHONY: clean context clean_context distclean + +$(OBJS): %.o1: %.c + $(HOSTCC) -c $(HOSTCFLAGS) $< -o $@ + +include: + @mkdir include + +include/net: include + @ln -s $(TOPDIR)/include/net include/net + +include/nuttx: + @mkdir -p include/nuttx + +include/queue.h: include + @cp -a $(TOPDIR)/include/queue.h include/. + +include/nuttx/config.h: include/nuttx + @touch include/nuttx/config.h + +headers: include/nuttx/config.h include/queue.h include/net + +$(BIN): headers $(OBJS) + $(HOSTCC) $(HOSTLDFLAGS) $(OBJS) -o $@ + +clean: + @rm -f $(BIN).* *.o1 *~ + @rm -rf include + + diff --git a/apps/examples/sendmail/host.c b/apps/examples/sendmail/host.c new file mode 100644 index 000000000..67a541b0c --- /dev/null +++ b/apps/examples/sendmail/host.c @@ -0,0 +1,103 @@ +/**************************************************************************** + * examples/sendmail/host.c + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <apps/netutils/smtp.h> + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_host_name[] = "localhost"; +static const char g_sender[] = "nuttx-testing@example.com"; +static const char g_subject[] = "Testing SMTP from NuttX"; +static const char g_msg_body[] = "Test message sent by NuttX\r\n"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: show_usage + ****************************************************************************/ + +static void show_usage(const char *progname, int exitcode) +{ + fprintf(stderr, "USAGE: %s <recipient>\n", progname); + exit(exitcode); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/**************************************************************************** + * Name: main + ****************************************************************************/ + +int main(int argc, char **argv, char **envp) +{ + struct in_addr addr; + void *handle; + + if (argc != 2) + { + show_usage(argv[0], 1); + } + + printf("sendmail: To: %s\n", argv[1]); + printf("sendmail: From: %s\n", g_sender); + printf("sendmail: Subject: %s\n", g_subject); + printf("sendmail: Body: %s\n", g_msg_body); + + uip_ipaddr(addr.s_addr, 127, 0, 0, 1); + handle = smtp_open(); + if (handle) + { + smtp_configure(handle, g_host_name, &addr.s_addr); + smtp_send(handle, argv[1], NULL, g_sender, g_subject, + g_msg_body, strlen(g_msg_body)); + smtp_close(handle); + } + return 0; +} diff --git a/apps/examples/sendmail/hostdefs.h b/apps/examples/sendmail/hostdefs.h new file mode 100755 index 000000000..da072d560 --- /dev/null +++ b/apps/examples/sendmail/hostdefs.h @@ -0,0 +1,69 @@ +/****************************************************************************
+ * examples/wget/hostdefs.c
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __HOSTDEFS_H
+#define __HOSTDEFS_H
+
+/****************************************************************************
+ * Included Files
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+/****************************************************************************
+ * Preprocessor Defintiions
+ *****************************************************************************/
+
+#define HTONS(a) htons(a)
+#define HTONL(a) htonl(a)
+#define CONFIG_CPP_HAVE_WARNING 1
+#define CONFIG_HAVE_GETHOSTBYNAME 1
+#define FAR
+
+#define ndbg(...) printf(__VA_ARGS__)
+#define nvdbg(...) printf(__VA_ARGS__)
+
+#define ERROR (-1)
+#define OK (0)
+
+/****************************************************************************
+ * Type Definitions
+ *****************************************************************************/
+
+typedef void *(*pthread_startroutine_t)(void *);
+
+#endif /* __HOSTDEFS_H */
diff --git a/apps/examples/sendmail/target.c b/apps/examples/sendmail/target.c new file mode 100644 index 000000000..ab4da14b1 --- /dev/null +++ b/apps/examples/sendmail/target.c @@ -0,0 +1,157 @@ +/**************************************************************************** + * examples/sendmail/target.c + * + * Copyright (C) 2009. 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <net/if.h> +#include <apps/netutils/uiplib.h> +#include <apps/netutils/smtp.h> + +/**************************************************************************** + * Pre-processor Defintitions + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLE_SENDMAIL_RECIPIENT +# error "You must provice CONFIG_EXAMPLE_SENDMAIL_RECIPIENT" +#endif + +#ifndef CONFIG_EXAMPLE_SENDMAIL_IPADDR +# error "You must provice CONFIG_EXAMPLE_SENDMAIL_IPADDR" +#endif + +#ifndef CONFIG_EXAMPLE_SENDMAIL_DRIPADDR +# error "You must provice CONFIG_EXAMPLE_SENDMAIL_DRIPADDR" +#endif + +#ifndef CONFIG_EXAMPLE_SENDMAIL_NETMASK +# error "You must provice CONFIG_EXAMPLE_SENDMAIL_NETMASK" +#endif + +#ifndef CONFIG_EXAMPLE_SENDMAIL_SENDER +# define CONFIG_EXAMPLE_SENDMAIL_SENDER "nuttx-testing@example.com" +#endif + +#ifndef CONFIG_EXAMPLE_SENDMAIL_SUBJECT +# define CONFIG_EXAMPLE_SENDMAIL_SUBJECT "Testing SMTP from NuttX" +#endif + +#ifndef CONFIG_EXAMPLE_SENDMAIL_BODY +# define CONFIG_EXAMPLE_SENDMAIL_BODY "Test message sent by NuttX" +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_host_name[] = "localhost"; +static const char g_recipient[] = CONFIG_EXAMPLE_SENDMAIL_RECIPIENT; +static const char g_sender[] = CONFIG_EXAMPLE_SENDMAIL_SENDER; +static const char g_subject[] = CONFIG_EXAMPLE_SENDMAIL_SUBJECT; +static const char g_msg_body[] = CONFIG_EXAMPLE_SENDMAIL_BODY "\r\n"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + struct in_addr addr; +#if defined(CONFIG_EXAMPLE_SENDMAIL_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif + void *handle; + + printf("sendmail: To: %s\n", g_recipient); + printf("sendmail: From: %s\n", g_sender); + printf("sendmail: Subject: %s\n", g_subject); + printf("sendmail: Body: %s\n", g_msg_body); + +/* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_SENDMAIL_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_SENDMAIL_IPADDR); + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_SENDMAIL_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_SENDMAIL_NETMASK); + uip_setnetmask("eth0", &addr); + + /* Then send the mail */ + + uip_ipaddr(addr.s_addr, 127, 0, 0, 1); + handle = smtp_open(); + if (handle) + { + smtp_configure(handle, g_host_name, &addr.s_addr); + smtp_send(handle, g_recipient, NULL, g_sender, g_subject, + g_msg_body, strlen(g_msg_body)); + smtp_close(handle); + } + return 0; +} diff --git a/apps/examples/serloop/Makefile b/apps/examples/serloop/Makefile new file mode 100644 index 000000000..67c805d46 --- /dev/null +++ b/apps/examples/serloop/Makefile @@ -0,0 +1,95 @@ +############################################################################ +# apps/examples/serloop/Makefile +# +# Copyright (C) 2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Mindlessly simple console loopack test + +ASRCS = +CSRCS = main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +# Register application +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/serloop/main.c b/apps/examples/serloop/main.c new file mode 100644 index 000000000..3c635fe88 --- /dev/null +++ b/apps/examples/serloop/main.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * examples/serloop/main.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ +#ifdef CONFIG_EXAMPLES_SERLOOP_BUFIO + int ch; + + for (;;) + { + ch = getchar(); + if (ch < 1) + { + ch = '!'; + } + else if ((ch < 0x20 || ch > 0x7e) && ch != '\n') + { + ch = '.'; + } + putchar(ch); + } +#else + uint8_t ch; + int ret; + + for (;;) + { + ret = read(0, &ch, 1); + if (ret < 1) + { + ch = '!'; + } + else if ((ch < 0x20 || ch > 0x7e) && ch != '\n') + { + ch = '.'; + } + ret = write(1, &ch, 1); + } +#endif + return 0; +} + diff --git a/apps/examples/thttpd/Makefile b/apps/examples/thttpd/Makefile new file mode 100644 index 000000000..9df26af35 --- /dev/null +++ b/apps/examples/thttpd/Makefile @@ -0,0 +1,98 @@ +############################################################################ +# apps/examples/thttpd/Makefile +# +# Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# THTTPD Web Server Example + +ASRCS = +CSRCS = main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: headers clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +headers: + @$(MAKE) -C content TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) + +.built: headers $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + @$(MAKE) -C content clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/thttpd/content/Makefile b/apps/examples/thttpd/content/Makefile new file mode 100644 index 000000000..8c213a9d5 --- /dev/null +++ b/apps/examples/thttpd/content/Makefile @@ -0,0 +1,104 @@ +############################################################################ +# apps/examples/thttpd/content/Makefile +# +# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +SUBDIRS = hello tasks netstat +INSTALL_FILES = index.html style.css + +THTTPD_DIR = $(APPDIR)/examples/thttpd +CONTENT_DIR = $(THTTPD_DIR)/content +ROMFS_DIR = $(CONTENT_DIR)/romfs +ROMFS_IMG = $(CONTENT_DIR)/romfs.img +ROMFS_HDR = $(CONTENT_DIR)/romfs.h +ROMFSCGI_DIR = $(ROMFS_DIR)/cgi-bin +SYMTAB = $(CONTENT_DIR)/symtab.h + +define DIR_template +$(1)_$(2): + @$(MAKE) -C $(1) $(3) TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) CGI_DIR="$(ROMFSCGI_DIR)" +endef + +all: $(ROMFS_HDR) $(SYMTAB) +.PHONY: all build clean install populate + +$(foreach DIR, $(SUBDIRS), $(eval $(call DIR_template,$(DIR),build, all))) +$(foreach DIR, $(SUBDIRS), $(eval $(call DIR_template,$(DIR),clean,clean))) +$(foreach DIR, $(SUBDIRS), $(eval $(call DIR_template,$(DIR),install,install))) + +# Build program(s) in each sud-directory + +build: $(foreach DIR, $(SUBDIRS), $(DIR)_build) + +# Install each program in the romfs directory + +install: $(foreach DIR, $(SUBDIRS), $(DIR)_install) + @( for file in $(INSTALL_FILES); do\ + install -m 0644 -D $${file} $(ROMFS_DIR)/$${file}; \ + done; ) + +# Create the romfs directory + +$(ROMFS_DIR): + @mkdir -p $(ROMFS_DIR) + +$(ROMFSCGI_DIR): $(ROMFS_DIR) + @mkdir -p $(ROMFSCGI_DIR) + +# Populate the romfs directory + +populate: $(ROMFSCGI_DIR) build install + +# Create the romfs.img file from the populated romfs directory + +$(ROMFS_IMG): populate + @genromfs -f $@ -d $(ROMFS_DIR) -V "THTTPDTEST" + +# Create the romfs.h header file from the romfs.img file + +$(ROMFS_HDR) : $(ROMFS_IMG) + @(cd $(CONTENT_DIR); xxd -i romfs.img | sed -e "s/^unsigned/static const unsigned/g" >$@) + +# Create the exported symbol table list from the derived *-thunk.S files + +$(SYMTAB): build + @$(CONTENT_DIR)/mksymtab.sh $(CONTENT_DIR) >$@ + +# Clean each subdirectory + +clean: $(foreach DIR, $(SUBDIRS), $(DIR)_clean) + @rm -f $(ROMFS_HDR) $(ROMFS_IMG) $(SYMTAB) + @rm -rf $(ROMFS_DIR) + @rm -f *~ .*.swp + + diff --git a/apps/examples/thttpd/content/hello/Makefile b/apps/examples/thttpd/content/hello/Makefile new file mode 100644 index 000000000..e980f1c34 --- /dev/null +++ b/apps/examples/thttpd/content/hello/Makefile @@ -0,0 +1,78 @@ +############################################################################ +# examples/thttpd/content/hello/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = hello + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -m 0755 -D $(BIN) $(CGI_DIR)/$(BIN) + diff --git a/apps/examples/thttpd/content/hello/hello.c b/apps/examples/thttpd/content/hello/hello.c new file mode 100644 index 000000000..40f31a454 --- /dev/null +++ b/apps/examples/thttpd/content/hello/hello.c @@ -0,0 +1,79 @@ +/**************************************************************************** + * examples/thttpd/content/hello/hello.c + * Manatory "Hello, World!" Example + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char *argv[]) +{ + fprintf(stderr, "Hello requested from: %s\n", getenv("REMOTE_ADDR")); + + puts( + "Content-type: text/html\r\n" + "Status: 200/html\r\n" + "\r\n" + "<html>\r\n" + "<head>\r\n" + "<title>Hello!</title>\r\n" + "<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">\r\n" + "</head>\r\n" + "<body bgcolor=\"#fffeec\" text=\"black\">\r\n" + "<div class=\"menu\">\r\n" + "<div class=\"menubox\"><a href=\"/index.html\">Front page</a></div>\r\n" + "<div class=\"menubox\"><a href=\"hello\">Say Hello</a></div>\r\n" + "<div class=\"menubox\"><a href=\"tasks\">Tasks</a></div>\r\n" + "<div class=\"menubox\"><a href=\"netstat\">Network status</a></div>\r\n" + "<br>\r\n" + "</div>\r\n" + "<div class=\"contentblock\">\r\n"); + printf( + "<h2>Hello, World!</h2><p>Requested by: %s</p>\r\n", + getenv("REMOTE_ADDR")); + puts( + "</body>\r\n" + "</html>\r\n"); + return 0; +} diff --git a/apps/examples/thttpd/content/index.html b/apps/examples/thttpd/content/index.html new file mode 100644 index 000000000..1fba1fbf6 --- /dev/null +++ b/apps/examples/thttpd/content/index.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> + <head> + <title>NuttX examples/thttpd</title> + <link rel="stylesheet" type="text/css" href="style.css"> + </head> + <body bgcolor="#fffeec" text="black"> + + <div class="menu"> + <div class="menubox"><a href="index.html">Front page</a></div> + <div class="menubox"><a href="cgi-bin/hello">Say Hello</a></div> + <div class="menubox"><a href="cgi-bin/tasks">Tasks</a></div> + <div class="menubox"><a href="cgi-bin/netstat">Network status</a></div> + <br> + </div> + + <div class="contentblock"> + <p> + These web pages are served by a port of <a href="http://acme.com/software/thttpd/">THTTPD</a> + running on top of <a href="http://www.nuttx.org">NuttX</a>. + NuttX includes a port of the <a href="http://www.sics.se/~adam/uip/">uIP</a> embedded TCP/IP stack. + </p> + <p> + Click on the links above to exercise THTTPD's CGI capability under NuttX. + Clicking the links will execute the CGI program from an + <a href="http://nuttx.sourceforge.net/NuttXNxFlat.html">NXFLAT</a> program residing + in a ROMFS file system. + </p> + </body> +</html> diff --git a/apps/examples/thttpd/content/mksymtab.sh b/apps/examples/thttpd/content/mksymtab.sh new file mode 100755 index 000000000..611d3a87a --- /dev/null +++ b/apps/examples/thttpd/content/mksymtab.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +usage="Usage: %0 <test-dir-path>" + +dir=$1 +if [ -z "$dir" ]; then + echo "ERROR: Missing <test-dir-path>" + echo "" + echo $usage + exit 1 +fi + +if [ ! -d "$dir" ]; then + echo "ERROR: Directory $dir does not exist" + echo "" + echo $usage + exit 1 +fi + +varlist=`find $dir -name "*-thunk.S"| xargs grep -h asciz | cut -f3 | sort | uniq` + +echo "#ifndef __EXAMPLES_NXFLAT_TESTS_SYMTAB_H" +echo "#define __EXAMPLES_NXFLAT_TESTS_SYMTAB_H" +echo "" +echo "#include <nuttx/symtab.h>" +echo "" +echo "static const struct symtab_s exports[] = " +echo "{" + +for string in $varlist; do + var=`echo $string | sed -e "s/\"//g"` + echo " {$string, $var}," +done + +echo "};" +echo "#define NEXPORTS (sizeof(exports)/sizeof(struct symtab_s))" +echo "" +echo "#endif /* __EXAMPLES_NXFLAT_TESTS_SYMTAB_H */" + diff --git a/apps/examples/thttpd/content/netstat/Makefile b/apps/examples/thttpd/content/netstat/Makefile new file mode 100644 index 000000000..b12cbabc8 --- /dev/null +++ b/apps/examples/thttpd/content/netstat/Makefile @@ -0,0 +1,78 @@ +############################################################################ +# examples/thttpd/content/netstat/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = netstat + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -m 0755 -D $(BIN) $(CGI_DIR)/$(BIN) + diff --git a/apps/examples/thttpd/content/netstat/netstat.c b/apps/examples/thttpd/content/netstat/netstat.c new file mode 100755 index 000000000..634146274 --- /dev/null +++ b/apps/examples/thttpd/content/netstat/netstat.c @@ -0,0 +1,134 @@ +/**************************************************************************** + * examples/thttpd/netstat/netstat.c + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <netinet/ether.h> +#include <net/uip/uipopt.h> +#include <net/uip/uip-arch.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* NOTEs: + * + * 1. One limitation in the use of NXFLAT is that functions that are + * referenced as a pointer-to-a-function must have global scope. Otherwise + * ARM GCC will generate some bad logic. + * 2. In general, when called back, there is no guarantee to that PIC registers + * will be valid and, unless you take special precautions, it could be + * dangerous to reference global variables in the callback function. + */ + +/* static */ int netdev_callback(FAR struct uip_driver_s *dev, void *arg) +{ + struct in_addr addr; + + printf(" <dt>%s\r\n", dev->d_ifname); +#ifdef CONFIG_NET_ETHERNET + printf(" <dd>HWaddr: %s<br>\r\n", ether_ntoa(&dev->d_mac)); +#endif + addr.s_addr = dev->d_ipaddr; + printf(" IPaddr: %s<br>\r\n", inet_ntoa(addr)); + addr.s_addr = dev->d_draddr; + printf(" DRaddr: %s<br>\r\n", inet_ntoa(addr)); + addr.s_addr = dev->d_netmask; + printf(" Mask: %s\r\n", inet_ntoa(addr)); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char *argv[]) +{ + puts( + "Content-type: text/html\r\n" + "Status: 200/html\r\n" + "\r\n" + "<html>\r\n" + "<head>\r\n" + "<title>Network Status</title>\r\n" + "<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">\r\n" + "</head>\r\n" + "<body bgcolor=\"#fffeec\" text=\"black\">\r\n" + "<div class=\"menu\">\r\n" + "<div class=\"menubox\"><a href=\"/index.html\">Front page</a></div>\r\n" + "<div class=\"menubox\"><a href=\"hello\">Say Hello</a></div>\r\n" + "<div class=\"menubox\"><a href=\"tasks\">Tasks</a></div>\r\n" + "<div class=\"menubox\"><a href=\"netstat\">Network status</a></div>\r\n" + "<br>\r\n" + "</div>\r\n" + "<div class=\"contentblock\">\r\n" + "<dl>\r\n"); + + netdev_foreach(netdev_callback, NULL); + + puts( + "</dl>\r\n" + "</body>\r\n" + "</html>\r\n"); + return 0; +} diff --git a/apps/examples/thttpd/content/style.css b/apps/examples/thttpd/content/style.css new file mode 100644 index 000000000..bfb0997a8 --- /dev/null +++ b/apps/examples/thttpd/content/style.css @@ -0,0 +1,80 @@ +h1 +{ + text-align: center; + font-size:14pt; + font-family:arial,helvetica; + font-weight:bold; + padding:10px; +} + +body +{ + background-color: #fffeec; + color:black; + font-size:8pt; + font-family:arial,helvetica; +} + +.menu +{ + margin: 4px; + width:60%; + padding:2px; + border: solid 1px; + background-color: #fffcd2; + text-align:left; + font-size:9pt; + font-family:arial,helvetica; +} + +div.menubox +{ + width: 25%; + border: 0; + float: left; + text-align: center; +} + +.contentblock +{ + margin: 4px; + width:60%; + padding:2px; + border: 1px dotted; + background-color: white; + font-size:8pt; + font-family:arial,helvetica; +} + +p.intro +{ + margin-left:20px; + margin-right:20px; + font-size:10pt; + font-family:arial,helvetica; +} + +p.clink +{ + font-size:12pt; + font-family:courier,monospace; + text-align:center; +} + +p.clink9 +{ + font-size:9pt; + font-family:courier,monospace; + text-align:center; +} + +p +{ + padding-left:10px; +} + +p.right +{ + text-align:right; +} + diff --git a/apps/examples/thttpd/content/tasks/Makefile b/apps/examples/thttpd/content/tasks/Makefile new file mode 100755 index 000000000..2666e0b69 --- /dev/null +++ b/apps/examples/thttpd/content/tasks/Makefile @@ -0,0 +1,78 @@ +############################################################################ +# examples/thttpd/content/tasks/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +BIN = tasks + +R1SRCS = $(BIN).c +R1OBJS = $(R1SRCS:.c=.o) + +R2SRC = $(BIN)-thunk.S +R2OBJ = $(R2SRC:.S=.o) + +all: $(BIN) + +$(R1OBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2OBJ): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(BIN).r1: $(R1OBJS) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC): $(BIN).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN).r2: $(R2OBJ) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS) $(R2OBJ) + +$(BIN): $(BIN).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN) $(R2SRC) *.o *.r1 *.r2 *~ .*.swp core + +install: + @install -m 0755 -D $(BIN) $(CGI_DIR)/$(BIN) + diff --git a/apps/examples/thttpd/content/tasks/tasks.c b/apps/examples/thttpd/content/tasks/tasks.c new file mode 100755 index 000000000..780569090 --- /dev/null +++ b/apps/examples/thttpd/content/tasks/tasks.c @@ -0,0 +1,176 @@ +/**************************************************************************** + * examples/thttpd/tasks/tasks.c + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sched.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char *g_statenames[] = +{ + "INVALID ", + "PENDING ", + "READY ", + "RUNNING ", + "INACTIVE", + "WAITSEM ", +#ifndef CONFIG_DISABLE_MQUEUE + "WAITSIG ", +#endif +#ifndef CONFIG_DISABLE_MQUEUE + "MQNEMPTY", + "MQNFULL " +#endif +}; + +static const char *g_ttypenames[4] = +{ + "TASK ", + "PTHREAD", + "KTHREAD", + "--?-- " +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* NOTEs: + * + * 1. One limitation in the use of NXFLAT is that functions that are + * referenced as a pointer-to-a-function must have global scope. Otherwise + * ARM GCC will generate some bad logic. + * 2. In general, when called back, there is no guarantee to that PIC registers + * will be valid and, unless you take special precautions, it could be + * dangerous to reference global variables in the callback function. + */ + +/* static */ void show_task(FAR _TCB *tcb, FAR void *arg) +{ + int i; + + /* Show task status */ + + printf("%5d %3d %4s %7s%c%c %8s ", + tcb->pid, tcb->sched_priority, + tcb->flags & TCB_FLAG_ROUND_ROBIN ? "RR " : "FIFO", + g_ttypenames[(tcb->flags & TCB_FLAG_TTYPE_MASK) >> TCB_FLAG_TTYPE_SHIFT], + tcb->flags & TCB_FLAG_NONCANCELABLE ? 'N' : ' ', + tcb->flags & TCB_FLAG_CANCEL_PENDING ? 'P' : ' ', + g_statenames[tcb->task_state]); + + /* Show task name and arguments */ + + printf("%s(", tcb->argv[0]); + + /* Special case 1st argument (no comma) */ + + if (tcb->argv[1]) + { + printf("%p", tcb->argv[1]); + } + + /* Then any additional arguments */ + +#if CONFIG_MAX_TASK_ARGS > 2 + for (i = 2; i <= CONFIG_MAX_TASK_ARGS && tcb->argv[i]; i++) + { + printf(", %p", tcb->argv[i]); + } +#endif + printf(")\n"); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char *argv[]) +{ + puts( + "Content-type: text/html\r\n" + "Status: 200/html\r\n" + "\r\n" + "<html>\r\n" + "<head>\r\n" + "<title>NuttX Tasks</title>\r\n" + "<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">\r\n" + "</head>\r\n" + "<body bgcolor=\"#fffeec\" text=\"black\">\r\n" + "<div class=\"menu\">\r\n" + "<div class=\"menubox\"><a href=\"/index.html\">Front page</a></div>\r\n" + "<div class=\"menubox\"><a href=\"hello\">Say Hello</a></div>\r\n" + "<div class=\"menubox\"><a href=\"tasks\">Tasks</a></div>\r\n" + "<div class=\"menubox\"><a href=\"netstat\">Network status</a></div>\r\n" + "<br>\r\n" + "</div>\r\n" + "<div class=\"contentblock\">\r\n" + "<pre>\r\n" + "PID PRI SCHD TYPE NP STATE NAME\r\n"); + + sched_foreach(show_task, NULL); + + puts( + "</pre>\r\n" + "</body>\r\n" + "</html>\r\n"); + return 0; +} diff --git a/apps/examples/thttpd/main.c b/apps/examples/thttpd/main.c new file mode 100644 index 000000000..be30876cb --- /dev/null +++ b/apps/examples/thttpd/main.c @@ -0,0 +1,267 @@ +/**************************************************************************** + * examples/thttpd/main.c + * + * Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/ioctl.h> +#include <sys/mount.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <debug.h> + +#include <net/if.h> +#include <netinet/ether.h> + +#include <net/uip/uip-arp.h> +#include <apps/netutils/uiplib.h> +#include <apps/netutils/thttpd.h> + +#include <nuttx/ramdisk.h> +#include <nuttx/binfmt.h> +#include <nuttx/nxflat.h> +#ifdef CONFIG_NET_SLIP +# include <nuttx/net.h> +#endif + +#include "content/romfs.h" +#include "content/symtab.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Check configuration. This is not all of the configuration settings that + * are required -- only the more obvious. + */ + +#if CONFIG_NFILE_DESCRIPTORS < 1 +# error "You must provide file descriptors via CONFIG_NFILE_DESCRIPTORS in your configuration file" +#endif + +#ifndef CONFIG_NXFLAT +# error "You must select CONFIG_NXFLAT in your configuration file" +#endif + +#ifndef CONFIG_FS_ROMFS +# error "You must select CONFIG_FS_ROMFS in your configuration file" +#endif + +#ifdef CONFIG_DISABLE_MOUNTPOINT +# error "You must not disable mountpoints via CONFIG_DISABLE_MOUNTPOINT in your configuration file" +#endif + +#ifdef CONFIG_BINFMT_DISABLE +# error "You must not disable loadable modules via CONFIG_BINFMT_DISABLE in your configuration file" +#endif + +/* SLIP-specific configuration */ + +#ifdef CONFIG_NET_SLIP + + /* No MAC address operations */ + +# undef CONFIG_EXAMPLE_THTTPD_NOMAC + + /* TTY device to use */ + +# ifndef CONFIG_NET_SLIPTTY +# define CONFIG_NET_SLIPTTY "/dev/ttyS1" +# endif + +# define SLIP_DEVNO 0 +# define NET_DEVNAME "sl0" +#else + + /* Otherwise, use the standard ethernet device name */ + +# define NET_DEVNAME "eth0" +#endif + +/* Describe the ROMFS file system */ + +#define SECTORSIZE 512 +#define NSECTORS(b) (((b)+SECTORSIZE-1)/SECTORSIZE) +#define ROMFSDEV "/dev/ram0" +#define MOUNTPT CONFIG_THTTPD_PATH + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* These values must be provided by the user before the THTTPD task daemon + * is started: + * + * g_thttpdsymtab: A symbol table describing all of the symbols exported + * from the base system. These symbols are used to bind address references + * in CGI programs to NuttX. + * g_nsymbols: The number of symbols in g_thttpdsymtab[]. + */ + +FAR const struct symtab_s *g_thttpdsymtab; +int g_thttpdnsymbols; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + struct in_addr addr; +#ifdef CONFIG_EXAMPLE_THTTPD_NOMAC + uint8_t mac[IFHWADDRLEN]; +#endif + char *thttpd_argv = "thttpd"; + int ret; + + /* Configure SLIP */ + +#ifdef CONFIG_NET_SLIP + ret = slip_initialize(SLIP_DEVNO, CONFIG_NET_SLIPTTY); + if (ret < 0) + { + message("ERROR: SLIP initialization failed: %d\n", ret); + exit(1); + } +#endif + +/* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_THTTPD_NOMAC + message("Assigning MAC\n"); + + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr(NET_DEVNAME, mac); +#endif + + /* Set up our host address */ + + message("Setup network addresses\n"); + addr.s_addr = HTONL(CONFIG_THTTPD_IPADDR); + uip_sethostaddr(NET_DEVNAME, &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_THTTPD_DRIPADDR); + uip_setdraddr(NET_DEVNAME, &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_THTTPD_NETMASK); + uip_setnetmask(NET_DEVNAME, &addr); + + /* Initialize the NXFLAT binary loader */ + + message("Initializing the NXFLAT binary loader\n"); + ret = nxflat_initialize(); + if (ret < 0) + { + message("ERROR: Initialization of the NXFLAT loader failed: %d\n", ret); + exit(2); + } + + /* Create a ROM disk for the ROMFS filesystem */ + + message("Registering romdisk\n"); + ret = romdisk_register(0, (uint8_t*)romfs_img, NSECTORS(romfs_img_len), SECTORSIZE); + if (ret < 0) + { + message("ERROR: romdisk_register failed: %d\n", ret); + nxflat_uninitialize(); + exit(1); + } + + /* Mount the file system */ + + message("Mounting ROMFS filesystem at target=%s with source=%s\n", + MOUNTPT, ROMFSDEV); + + ret = mount(ROMFSDEV, MOUNTPT, "romfs", MS_RDONLY, NULL); + if (ret < 0) + { + message("ERROR: mount(%s,%s,romfs) failed: %s\n", + ROMFSDEV, MOUNTPT, errno); + nxflat_uninitialize(); + } + + /* Start THTTPD. At present, symbol table info is passed via global variables */ + + g_thttpdsymtab = exports; + g_thttpdnsymbols = NEXPORTS; + + message("Starting THTTPD\n"); + msgflush(); + thttpd_main(1, &thttpd_argv); + message("THTTPD terminated\n"); + msgflush(); + return 0; +} diff --git a/apps/examples/tiff/Makefile b/apps/examples/tiff/Makefile new file mode 100644 index 000000000..045508d14 --- /dev/null +++ b/apps/examples/tiff/Makefile @@ -0,0 +1,106 @@ +############################################################################ +# apps/examples/tiff/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# TIFF Unit Test + +ASRCS = +CSRCS = tiff_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# TIFF built-in application info + +APPNAME = tiff +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_TIFF_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + @rm -f result.tif tmpfile1.dat tmpfile2.dat + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/tiff/tiff_main.c b/apps/examples/tiff/tiff_main.c new file mode 100644 index 000000000..d59f42cb4 --- /dev/null +++ b/apps/examples/tiff/tiff_main.c @@ -0,0 +1,174 @@ +/**************************************************************************** + * apps/graphics/tiff/tiff_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> + +#include <apps/tiff.h> + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* This is a simple unit test for the TIFF creation library at apps/graphic/tiff. + * It is configured to work in the Linux user-mode simulation and has not been + * tested in any other environment. Since the example also depends on some + * other logic to mount a file system, currently it will only work as an NSH + * built-on, i.e., if the following is defined: + * + * CONFIG_NSH_BUILTIN_APPS=y + * CONFIG_EXAMPLES_TIFF_BUILTIN=y + * + * Other configuration options: + * + * CONFIG_EXAMPLES_TIFF_OUTFILE - Name of the resulting TIFF file + * CONFIG_EXAMPLES_TIFF_TMPFILE1/2 - Names of two temporaries files that + * will be used in the file creation. + */ + +#ifndef CONFIG_EXAMPLES_TIFF_OUTFILE +# define CONFIG_EXAMPLES_TIFF_OUTFILE "/tmp/result.tif" +#endif + +#ifndef CONFIG_EXAMPLES_TIFF_TMPFILE1 +# define CONFIG_EXAMPLES_TIFF_TMPFILE1 "/tmp/tmpfile1.dat" +#endif + +#ifndef CONFIG_EXAMPLES_TIFF_TMPFILE2 +# define CONFIG_EXAMPLES_TIFF_TMPFILE2 "/tmp/tmpfile2.dat" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiff_main/user_start + * + * Description: + * TIFF unit test. + * + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_TIFF_BUILTIN +# define MAIN_NAME tiff_main +#else +# define MAIN_NAME user_start +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + struct tiff_info_s info; + uint8_t strip[3*256]; + uint8_t *ptr; + int green; + int blue; + int ret; + + /* Configure the interface structure */ + + memset(&info, 0, sizeof(struct tiff_info_s)); + info.outfile = CONFIG_EXAMPLES_TIFF_OUTFILE; + info.tmpfile1 = CONFIG_EXAMPLES_TIFF_TMPFILE1; + info.tmpfile2 = CONFIG_EXAMPLES_TIFF_TMPFILE2; + info.colorfmt = FB_FMT_RGB24; + info.rps = 1; + info.imgwidth = 256; + info.imgheight = 256; + info.iobuffer = (uint8_t *)malloc(300); + info.iosize = 300; + + /* Initialize the TIFF library */ + + ret = tiff_initialize(&info); + if (ret < 0) + { + printf("tiff_initialize() failed: %d\n", ret); + exit(1); + } + + /* Add each strip to the TIFF file */ + + for (green = 0, ptr = strip; green < 256; green++) + { + ptr = strip; + for (blue = 0; blue < 256; blue++) + { + *ptr++ = (green + blue) >> 1; + *ptr++ = green; + *ptr++ = blue; + } + + ret = tiff_addstrip(&info, strip); + if (ret < 0) + { + printf("tiff_addstrip() #%d failed: %d\n", green, ret); + exit(1); + } + } + + /* Then finalize the TIFF file */ + + ret = tiff_finalize(&info); + if (ret < 0) + { + printf("tiff_finalize() failed: %d\n", ret); + exit(1); + } + return 0; +} diff --git a/apps/examples/touchscreen/Makefile b/apps/examples/touchscreen/Makefile new file mode 100644 index 000000000..e53a52cf9 --- /dev/null +++ b/apps/examples/touchscreen/Makefile @@ -0,0 +1,105 @@ +############################################################################ +# apps/examples/touchscreen/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttX NX Graphics Example. + +ASRCS = +CSRCS = tc_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Touchscreen built-in application info + +APPNAME = tc +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/examples/touchscreen/tc.h b/apps/examples/touchscreen/tc.h new file mode 100644 index 000000000..173ed491f --- /dev/null +++ b/apps/examples/touchscreen/tc.h @@ -0,0 +1,137 @@ +/**************************************************************************** + * examples/touchscreen/tc.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_TOUCHSCREEN_TC_H +#define __APPS_EXAMPLES_TOUCHSCREEN_TC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN - Build the touchscreen test as + * an NSH built-in function. Default: Built as a standalone problem + * CONFIG_EXAMPLES_TOUCHSCREEN_MINOR - The minor device number. Minor=N + * correspnds to touchscreen device /dev/input0. Note this value must + * with CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH. Default 0. + * CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH - The path to the touchscreen + * device. This must be consistent with CONFIG_EXAMPLES_TOUCHSCREEN_MINOR. + * Default: "/dev/input0" + * CONFIG_EXAMPLES_TOUCHSCREEN_NSAMPLES - If CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN + * is defined, then the number of samples is provided on the command line + * and this value is ignored. Otherwise, this number of samples is + * collected and the program terminates. Default: Samples are collected + * indefinitely. + */ + +#ifndef CONFIG_INPUT +# error "Input device support is not enabled (CONFIG_INPUT)" +#endif + +#ifndef CONFIG_EXAMPLES_TOUCHSCREEN_MINOR +# undef CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH +# define CONFIG_EXAMPLES_TOUCHSCREEN_MINOR 0 +# define CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH "/dev/input0" +#endif + +#ifndef CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH +# undef CONFIG_EXAMPLES_TOUCHSCREEN_MINOR +# define CONFIG_EXAMPLES_TOUCHSCREEN_MINOR 0 +# define CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH "/dev/input0" +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_rawprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_rawprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: arch_tcinitialize() + * + * Description: + * Perform architecuture-specific initialization of the touchscreen + * hardware. This interface must be provided by all configurations + * using apps/examples/touchscreen + * + ****************************************************************************/ + +int arch_tcinitialize(int minor); + +/**************************************************************************** + * Name: arch_tcuninitialize() + * + * Description: + * Perform architecuture-specific un-initialization of the touchscreen + * hardware. This interface must be provided by all configurations + * using apps/examples/touchscreen + * + ****************************************************************************/ + +void arch_tcuninitialize(void); + +#endif /* __APPS_EXAMPLES_TOUCHSCREEN_TC_H */ diff --git a/apps/examples/touchscreen/tc_main.c b/apps/examples/touchscreen/tc_main.c new file mode 100644 index 000000000..6db6af992 --- /dev/null +++ b/apps/examples/touchscreen/tc_main.c @@ -0,0 +1,214 @@ +/**************************************************************************** + * examples/touchscreen/tc_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/input/touchscreen.h> + +#include "tc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: user_start/nxhello_main + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN +# define MAIN_NAME tc_main +# define MAIN_STRING "tc_main: " +#else +# define MAIN_NAME user_start +# define MAIN_STRING "user_start: " +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + struct touch_sample_s sample; + ssize_t nbytes; +#if defined(CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN) || defined(CONFIG_EXAMPLES_TOUCHSCREEN_NSAMPLES) + long nsamples; +#endif + int fd; + int errval = 0; + int ret; + + /* If this example is configured as an NX add-on, then limit the number of + * samples that we collect before returning. Otherwise, we never return + */ + +#if defined(CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN) + nsamples = 1; + if (argc > 1) + { + nsamples = strtol(argv[1], NULL, 10); + } + message(MAIN_STRING "nsamples: %d\n", nsamples); +#elif defined(CONFIG_EXAMPLES_TOUCHSCREEN_NSAMPLES) + message(MAIN_STRING "nsamples: %d\n", CONFIG_EXAMPLES_TOUCHSCREEN_NSAMPLES); +#endif + + /* Initialization of the touchscreen hardware is performed by logic + * external to this test. + */ + + message(MAIN_STRING "Initializing external touschscreen device\n"); + ret = arch_tcinitialize(CONFIG_EXAMPLES_TOUCHSCREEN_MINOR); + if (ret != OK) + { + message(MAIN_STRING "arch_tcinitialize failed: %d\n", ret); + errval = 1; + goto errout; + } + + /* Open the touchscreen device for reading */ + + fd = open(CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH, O_RDONLY); + if (fd < 0) + { + message(MAIN_STRING "open %s failed: %d\n", + CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH, errno); + errval = 2; + goto errout_with_tc; + } + + /* Now loop the appropriate number of times, displaying the collected + * touchscreen samples. + */ + +#if defined(CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN) + for (; nsamples > 0; nsamples--) +#elif defined(CONFIG_EXAMPLES_TOUCHSCREEN_NSAMPLES) + for (nsamples = 0; nsamples < CONFIG_EXAMPLES_TOUCHSCREEN_NSAMPLES; nsamples++) +#else + for (;;) +#endif + { + /* Flush any output before the loop entered or from the previous pass + * through the loop. + */ + + msgflush(); + + /* Read one sample */ + + nbytes = read(fd, &sample, sizeof(struct touch_sample_s)); + ivdbg("Bytes read: %d\n", nbytes); + + /* Handle unexpected return values */ + + if (nbytes < 0) + { + errval = errno; + if (errval != EINTR) + { + message(MAIN_STRING "read %s failed: %d\n", + CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH, errval); + errval = 3; + goto errout_with_dev; + } + + message(MAIN_STRING "Interrupted read...\n"); + } + else if (nbytes != sizeof(struct touch_sample_s)) + { + message(MAIN_STRING "Unexpected read size=%d, expected=%d, Ignoring\n", + nbytes, sizeof(struct touch_sample_s)); + } + + /* Print the sample data on successful return */ + + else + { + message("Sample :\n"); + message(" npoints : %d\n", sample.npoints); + message("Point 1 :\n"); + message(" id : %d\n", sample.point[0].id); + message(" flags : %02x\n", sample.point[0].flags); + message(" x : %d\n", sample.point[0].x); + message(" y : %d\n", sample.point[0].y); + message(" h : %d\n", sample.point[0].h); + message(" w : %d\n", sample.point[0].w); + message(" pressure : %d\n", sample.point[0].pressure); + } + } + +errout_with_dev: + close(fd); +errout_with_tc: + arch_tcuninitialize(); +errout: + message("Terminating!\n"); + msgflush(); + return errval; +} diff --git a/apps/examples/udp/Makefile b/apps/examples/udp/Makefile new file mode 100644 index 000000000..a9361ba6e --- /dev/null +++ b/apps/examples/udp/Makefile @@ -0,0 +1,124 @@ +############################################################################ +# apps/examples/udp/Makefile +# +# Copyright (C) 2007-2008, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# UDP Test + +TARG_ASRCS = + +TARG_CSRCS = target.c +ifeq ($(CONFIG_EXAMPLE_UDP_SERVER),y) +TARG_CSRCS += udp-server.c +else +TARG_CSRCS += udp-client.c +endif + +TARG_AOBJS = $(TARG_ASRCS:.S=$(OBJEXT)) +TARG_COBJS = $(TARG_CSRCS:.c=$(OBJEXT)) + +TARG_SRCS = $(TARG_ASRCS) $(TARG_CSRCS) +TARG_OBJS = $(TARG_AOBJS) $(TARG_COBJS) + +ifeq ($(WINTOOL),y) + TARG_BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + TARG_BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +HOSTCFLAGS += -DCONFIG_EXAMPLE_UDP_HOST=1 +ifeq ($(CONFIG_EXAMPLE_UDP_SERVER),y) +HOSTCFLAGS += -DCONFIG_EXAMPLE_UDP_SERVER=1 \ + -DCONFIG_EXAMPLE_UDP_SERVERIP="$(CONFIG_EXAMPLE_UDP_SERVERIP)" +endif + +HOST_SRCS = host.c +ifeq ($(CONFIG_EXAMPLE_UDP_SERVER),y) +HOST_SRCS += udp-client.c +else +HOST_SRCS += udp-server.c +endif + +HOST_OBJS = $(HOST_SRCS:.c=.o) +HOST_BIN = host + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend disclean + +$(TARG_AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(TARG_COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +"$(TARG_BIN)": $(TARG_OBJS) $(HOST_BIN) + @( for obj in $(TARG_OBJS) ; do \ + $(call ARCHIVE, $@, $${obj}); \ + done ; ) + +$(HOST_OBJS): %.o: %.c + $(HOSTCC) -c $(HOSTCFLAGS) $< -o $@ + +$(HOST_BIN): $(HOST_OBJS) + $(HOSTCC) $(HOSTLDFLAGS) $(HOST_OBJS) -o $@ + +.built: $(TARG_BIN) $(HOST_BIN) + @touch .built + +context: + +.depend: Makefile $(TARG_SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(TARG_SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f $(TARG_BIN) $(HOST_BIN) *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/udp/host.c b/apps/examples/udp/host.c new file mode 100644 index 000000000..34fd96765 --- /dev/null +++ b/apps/examples/udp/host.c @@ -0,0 +1,63 @@ +/**************************************************************************** + * examples/udp/host.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "udp-internal.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * main + ****************************************************************************/ + +int main(int argc, char **argv, char **envp) +{ +#ifdef CONFIG_EXAMPLE_UDP_SERVER + send_client(); +#else + recv_server(); +#endif + + return 0; +} diff --git a/apps/examples/udp/target.c b/apps/examples/udp/target.c new file mode 100644 index 000000000..07fec0e75 --- /dev/null +++ b/apps/examples/udp/target.c @@ -0,0 +1,91 @@ +/**************************************************************************** + * examples/udp/nettest.c + * + * Copyright (C) 2007, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdio.h> +#include <debug.h> + +#include <net/uip/uip.h> +#include <apps/netutils/uiplib.h> + +#include "udp-internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + struct in_addr addr; + + /* Set up our host address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_UDP_IPADDR); + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_UDP_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_UDP_NETMASK); + uip_setnetmask("eth0", &addr); + +#ifdef CONFIG_EXAMPLE_UDP_SERVER + recv_server(); +#else + send_client(); +#endif + + return 0; +} diff --git a/apps/examples/udp/udp-client.c b/apps/examples/udp/udp-client.c new file mode 100644 index 000000000..545a3a6c3 --- /dev/null +++ b/apps/examples/udp/udp-client.c @@ -0,0 +1,133 @@ +/**************************************************************************** + * examples/udp/udp-client.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "udp-internal.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline void fill_buffer(unsigned char *buf, int offset) +{ + int ch; + int j; + + buf[0] = offset; + for (ch = 0x20, j = offset + 1; ch < 0x7f; ch++, j++) + { + if (j >= SENDSIZE) + { + j = 1; + } + buf[j] = ch; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void send_client(void) +{ + struct sockaddr_in server; + unsigned char outbuf[SENDSIZE]; + int sockfd; + int nbytes; + int offset; + + /* Create a new TCP socket */ + + sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + message("client socket failure %d\n", errno); + exit(1); + } + + /* Then send and receive 256 messages */ + + for (offset = 0; offset < 256; offset++) + { + /* Set up the output buffer */ + + fill_buffer(outbuf, offset); + + /* Send the message */ + + server.sin_family = AF_INET; + server.sin_port = HTONS(PORTNO); + server.sin_addr.s_addr = HTONL(CONFIG_EXAMPLE_UDP_SERVERIP); + + message("client: %d. Sending %d bytes\n", offset, SENDSIZE); + nbytes = sendto(sockfd, outbuf, SENDSIZE, 0, + (struct sockaddr*)&server, sizeof(struct sockaddr_in)); + message("client: %d. Sent %d bytes\n", offset, nbytes); + + if (nbytes < 0) + { + message("client: %d. sendto failed: %d\n", offset, errno); + close(sockfd); + exit(-1); + } + else if (nbytes != SENDSIZE) + { + message("client: %d. Bad send length: %d Expected: %d\n", + offset, nbytes, SENDSIZE); + close(sockfd); + exit(-1); + } + + /* Now, sleep a bit. No packets should be dropped due to overrunning + * the server. + */ + + sleep(2); + } + close(sockfd); +} diff --git a/apps/examples/udp/udp-internal.h b/apps/examples/udp/udp-internal.h new file mode 100644 index 000000000..94fe1e482 --- /dev/null +++ b/apps/examples/udp/udp-internal.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * examples/udp/udp-internal.h + * + * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_UIP_INTERNAL_H +#define __EXAMPLES_UIP_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLE_UDP_HOST +#else +# include <debug.h> +#endif + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLE_UDP_HOST + /* HTONS/L macros are unique to uIP */ + +# define HTONS(a) htons(a) +# define HTONL(a) htonl(a) + + /* Used printf for debug output */ + +# define message(...) printf(__VA_ARGS__) + + /* Have SO_LINGER */ + +#else + + /* If debug is enabled, use the synchronous lib_lowprintf so that the + * program output does not get disassociated in the debug output. + */ + +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# else +# define message(...) printf(__VA_ARGS__) +# endif + +#endif + +#define PORTNO 5471 + +#define ASCIISIZE (0x7f - 0x20) +#define SENDSIZE (ASCIISIZE+1) + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +extern void send_client(void); +extern void recv_server(void); + +#endif /* __EXAMPLES_UIP_INTERNAL_H */ diff --git a/apps/examples/udp/udp-server.c b/apps/examples/udp/udp-server.c new file mode 100644 index 000000000..495a71320 --- /dev/null +++ b/apps/examples/udp/udp-server.c @@ -0,0 +1,173 @@ +/**************************************************************************** + * examples/udp/udp-server.c + * + * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/socket.h> +#include <netinet/in.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +#include "udp-internal.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline int check_buffer(unsigned char *buf) +{ + int ret = 1; + int offset; + int ch; + int j; + + offset = buf[0]; + for (ch = 0x20, j = offset + 1; ch < 0x7f; ch++, j++) + { + if (j >= SENDSIZE) + { + j = 1; + } + if (buf[j] != ch) + { + message("server: Buffer content error for offset=%d, index=%d\n", offset, j); + ret = 0; + } + } + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void recv_server(void) +{ + struct sockaddr_in server; + struct sockaddr_in client; + in_addr_t tmpaddr; + unsigned char inbuf[1024]; + int sockfd; + int nbytes; + int optval; + int offset; + socklen_t addrlen; + + /* Create a new UDP socket */ + + sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + message("server: socket failure: %d\n", errno); + exit(1); + } + + /* Set socket to reuse address */ + + optval = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0) + { + message("server: setsockopt SO_REUSEADDR failure: %d\n", errno); + exit(1); + } + + /* Bind the socket to a local address */ + + server.sin_family = AF_INET; + server.sin_port = HTONS(PORTNO); + server.sin_addr.s_addr = HTONL(INADDR_ANY); + + if (bind(sockfd, (struct sockaddr*)&server, sizeof(struct sockaddr_in)) < 0) + { + message("server: bind failure: %d\n", errno); + exit(1); + } + + /* Then receive up to 256 packets of data */ + + for (offset = 0; offset < 256; offset++) + { + message("server: %d. Receiving up 1024 bytes\n", offset); + addrlen = sizeof(struct sockaddr_in); + nbytes = recvfrom(sockfd, inbuf, 1024, 0, + (struct sockaddr*)&client, &addrlen); + + tmpaddr = ntohl(client.sin_addr.s_addr); + message("server: %d. Received %d bytes from %d.%d.%d.%d:%d\n", + offset, nbytes, + tmpaddr >> 24, (tmpaddr >> 16) & 0xff, + (tmpaddr >> 8) & 0xff, tmpaddr & 0xff, + ntohs(client.sin_port)); + + if (nbytes < 0) + { + message("server: %d. recv failed: %d\n", offset, errno); + close(sockfd); + exit(-1); + } + + if (nbytes != SENDSIZE) + { + message("server: %d. recv size incorrect: %d vs %d\n", offset, nbytes, SENDSIZE); + close(sockfd); + exit(-1); + } + + if (offset < inbuf[0]) + { + message("server: %d. %d packets lost, resetting offset\n", offset, inbuf[0] - offset); + offset = inbuf[0]; + } + else if (offset > inbuf[0]) + { + message("server: %d. Bad offset in buffer: %d\n", offset, inbuf[0]); + close(sockfd); + exit(-1); + } + + if (!check_buffer(inbuf)) + { + message("server: %d. Bad buffer contents\n", offset); + close(sockfd); + exit(-1); + } + } + close(sockfd); +} diff --git a/apps/examples/uip/Makefile b/apps/examples/uip/Makefile new file mode 100644 index 000000000..bf1d39917 --- /dev/null +++ b/apps/examples/uip/Makefile @@ -0,0 +1,94 @@ +############################################################################ +# apps/examples/uip/Makefile +# +# Copyright (C) 2007-2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# uIP very tiny web server example + +ASRCS = +CSRCS = main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +epend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/uip/main.c b/apps/examples/uip/main.c new file mode 100644 index 000000000..fd2da4b8e --- /dev/null +++ b/apps/examples/uip/main.c @@ -0,0 +1,207 @@ +/**************************************************************************** + * examples/uip/main.c + * + * Copyright (C) 2007, 2009-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based on uIP which also has a BSD style license: + * + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Dunkels. + * 4. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/ioctl.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <debug.h> + +#include <net/if.h> +#include <net/uip/uip.h> +#include <net/uip/uip-arp.h> + +#include <apps/netutils/uiplib.h> + +#ifdef CONFIG_EXAMPLE_UIP_DHCPC +#include <arpa/inet.h> +#endif + +/* Here we include the header file for the application(s) we use in + * our project as defined in the config/<board-name>/defconfig file + */ + +/* DHCPC may be used in conjunction with any other feature (or not) */ + +#ifdef CONFIG_EXAMPLE_UIP_DHCPC +# include <apps/netutils/resolv.h> +# include <apps/netutils/dhcpc.h> +#endif + +/* Include uIP webserver definitions */ + +#include <apps/netutils/httpd.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# else +# define message(...) printf(__VA_ARGS__) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# else +# define message (void) +# endif +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + struct in_addr addr; +#if defined(CONFIG_EXAMPLE_UIP_DHCPC) || defined(CONFIG_EXAMPLE_UIP_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif +#ifdef CONFIG_EXAMPLE_UIP_DHCPC + void *handle; +#endif + +/* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_UIP_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + +#ifdef CONFIG_EXAMPLE_UIP_DHCPC + addr.s_addr = 0; +#else + addr.s_addr = HTONL(CONFIG_EXAMPLE_UIP_IPADDR); +#endif + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_UIP_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_UIP_NETMASK); + uip_setnetmask("eth0", &addr); + +#ifdef CONFIG_EXAMPLE_UIP_DHCPC + /* Set up the resolver */ + + resolv_init(); + + /* Get the MAC address of the NIC */ + + uip_getmacaddr("eth0", mac); + + /* Set up the DHCPC modules */ + + handle = dhcpc_open(&mac, IFHWADDRLEN); + + /* Get an IP address. Note: there is no logic here for renewing the address in this + * example. The address should be renewed in ds.lease_time/2 seconds. + */ + + printf("Getting IP address\n"); + if (handle) + { + struct dhcpc_state ds; + (void)dhcpc_request(handle, &ds); + uip_sethostaddr("eth1", &ds.ipaddr); + if (ds.netmask.s_addr != 0) + { + uip_setnetmask("eth0", &ds.netmask); + } + if (ds.default_router.s_addr != 0) + { + uip_setdraddr("eth0", &ds.default_router); + } + if (ds.dnsaddr.s_addr != 0) + { + resolv_conf(&ds.dnsaddr); + } + dhcpc_close(handle); + printf("IP: %s\n", inet_ntoa(ds.ipaddr)); + } +#endif + +#ifdef CONFIG_NET_TCP + printf("Starting webserver\n"); + httpd_init(); + httpd_listen(); +#endif + + while(1) + { + sleep(3); + printf("main: Still running\n"); +#if CONFIG_NFILE_DESCRIPTORS > 0 + fflush(stdout); +#endif + } + return 0; +} diff --git a/apps/examples/usbserial/Makefile b/apps/examples/usbserial/Makefile new file mode 100644 index 000000000..35c76ba89 --- /dev/null +++ b/apps/examples/usbserial/Makefile @@ -0,0 +1,95 @@ +############################################################################ +# apps/examples/usbserial/Makefile +# +# Copyright (C) 2008, 2010-2010 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# USB serial device example + +ASRCS = +CSRCS = main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + @$(MAKE) -f Makefile.host clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/usbserial/Makefile.host b/apps/examples/usbserial/Makefile.host new file mode 100644 index 000000000..cd9319ab3 --- /dev/null +++ b/apps/examples/usbserial/Makefile.host @@ -0,0 +1,67 @@ +############################################################################ +# apps/examples/usbserial/Makefile.host +# +# Copyright (C) 2008, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TOPDIR must be defined on the make command line + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs + +SRC = host.c +BIN = host$(EXEEXT) + +DEFINES = +ifeq ($(CONFIG_EXAMPLES_USBSERIAL_INONLY),y) +DEFINES += -DCONFIG_EXAMPLES_USBSERIAL_INONLY=1 +endif +ifeq ($(CONFIG_EXAMPLES_USBSERIAL_OUTONLY),y) +DEFINES += -DCONFIG_EXAMPLES_USBSERIAL_OUTONLY=1 +endif +ifeq ($(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL),y) +DEFINES += -DCONFIG_EXAMPLES_USBSERIAL_ONLYSMALL=1 +endif +ifeq ($(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG),y) +DEFINES += -DCONFIG_EXAMPLES_USBSERIAL_ONLYBIG=1 +endif + +all: $(BIN) + +$(BIN): $(SRC) + @$(HOSTCC) $(HOSTCFLAGS) $(DEFINES) $^ -o $@ + +clean: + @rm -f $(BIN) *~ .*.swp *.o + $(call CLEAN) + + diff --git a/apps/examples/usbserial/host.c b/apps/examples/usbserial/host.c new file mode 100644 index 000000000..751b7530c --- /dev/null +++ b/apps/examples/usbserial/host.c @@ -0,0 +1,293 @@ +/**************************************************************************** + * examples/usbserial/host.c + * + * Copyright (C) 2008 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <termios.h> +#include <fcntl.h> +#include <errno.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#if defined(CONFIG_EXAMPLES_USBSERIAL_INONLY) && defined(CONFIG_EXAMPLES_USBSERIAL_OUTONLY) +# error "Cannot define both CONFIG_EXAMPLES_USBSERIAL_INONLY and _OUTONLY" +#endif +#if defined(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL) && defined(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG) +# error "Cannot define both CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL and _ONLYBIG" +#endif + +#if !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG) && !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL) +# ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY +# define COUNTER_NEEDED 1 +# endif +#endif + +#define DEFAULT_TTYDEV "/dev/ttyUSB0" +#define BUFFER_SIZE 1024 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char *g_ttydev = DEFAULT_TTYDEV; + +#ifndef CONFIG_EXAMPLES_USBSERIAL_ONLYBIG +static const char g_shortmsg[] = "Sure... You betcha!!\n"; +#endif + +#ifndef CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL +static const char g_longmsg[] = + "I am proud to come to this city as the guest of your distinguished Mayor, " + "who has symbolized throughout the world the fighting spirit of West Berlin. " + "And I am proud to visit the Federal Republic with your distinguished Chancellor " + "who for so many years has committed Germany to democracy and freedom and " + "progress, and to come here in the company of my fellow American, General Clay, " + "who has been in this city during its great moments of crisis and will come " + "again if ever needed.\n" + "Two thousand years ago the proudest boast was \"civis Romanus sum.\" Today, " + "in the world of freedom, the proudest boast is \"Ich bin ein Berliner.\"\r\"" + "I appreciate my interpreter translating my German!\n" + "There are many people in the world who really don't understand, or say they " + "don't, what is the great issue between the free world and the Communist world. " + "Let them come to Berlin. There are some who say that communism is the wave of " + "the future. Let them come to Berlin. And there are some who say in Europe and " + "elsewhere we can work with the Communists. Let them come to Berlin. And there " + "are even a few who say that it is true that communism is an evil system, but it " + "permits us to make economic progress. Lass' sie nach Berlin kommen. Let them " + "come to Berlin.\n" + "Freedom has many difficulties and democracy is not perfect, but we have never " + "had to put a wall up to keep our people in, to prevent them from leaving us. I " + "want to say, on behalf of my countrymen, who live many miles away on the other " + "side of the Atlantic, who are far distant from you, that they take the greatest " + "pride that they have been able to share with you, even from a distance, the " + "story of the last 18 years. I know of no town, no city, that has been besieged " + "for 18 years that still lives with the vitality and the force, and the hope and " + "the determination of the city of West Berlin. While the wall is the most obvious " + "and vivid demonstration of the failures of the Communist system, for all the " + "world to see, we take no satisfaction in it, for it is, as your Mayor has said, " + "an offense not only against history but an offense against humanity, separating " + "families, dividing husbands and wives and brothers and sisters, and dividing a " + "people who wish to be joined together.\n" + "What is true of this city is true of Germany--real, lasting peace in Europe can " + "never be assured as long as one German out of four is denied the elementary " + "right of free men, and that is to make a free choice. In 18 years of peace and " + "good faith, this generation of Germans has earned the right to be free, " + "including the right to unite their families and their nation in lasting peace, " + "with good will to all people. You live in a defended island of freedom, but " + "your life is part of the main. So let me ask you as I close, to lift your eyes " + "beyond the dangers of today, to the hopes of tomorrow, beyond the freedom merely " + "of this city of Berlin, or your country of Germany, to the advance of freedom " + "everywhere, beyond the wall to the day of peace with justice, beyond yourselves " + "and ourselves to all mankind.\n" + "Freedom is indivisible, and when one man is enslaved, all are not free. When all " + "are free, then we can look forward to that day when this city will be joined as " + "one and this country and this great Continent of Europe in a peaceful and hopeful " + "globe. When that day finally comes, as it will, the people of West Berlin can take " + "sober satisfaction in the fact that they were in the front lines for almost two " + "decades.\n" + "All free men, wherever they may live, are citizens of Berlin, and, therefore, " + "as a free man, I take pride in the words \"Ich bin ein Berliner.\"\n" + "President John F. Kennedy - June 26, 1963\n"; +#endif + +#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY +static char g_iobuffer[BUFFER_SIZE]; +#endif + +/**************************************************************************** + * show_usage + ****************************************************************************/ + +static void show_usage(const char *progname, int exitcode) +{ + fprintf(stderr, "USAGE: %s [<ttydev>]\n", progname); + exit(exitcode); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * main + ****************************************************************************/ + +int main(int argc, char **argv, char **envp) +{ + struct termios tty; +#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY + ssize_t nbytes; +#endif +#ifdef COUNTER_NEEDED + int count = 0; +#endif + int fd; + int ret; + + /* Handle input parameters */ + + if (argc > 1) + { + if (argc > 2) + { + fprintf(stderr, "Too many arguments on command line\n"); + show_usage(argv[0], 1); + } + g_ttydev = argv[1]; + } + + /* Open the USB serial device for blocking read/write */ + + do + { + printf("main: Opening USB serial driver\n"); + fd = open(g_ttydev, O_RDWR); + if (fd < 0) + { + printf("main: ERROR: Failed to open %s: %s\n", g_ttydev, strerror(errno)); + printf("main: Assume not connected. Wait and try again.\n"); + printf("main: (Control-C to terminate).\n"); + sleep(5); + } + } + while (fd < 0); + printf("main: Successfully opened the serial driver\n"); + + /* Configure the serial port in raw mode (at least turn off echo) */ + + ret = tcgetattr(fd, &tty); + if (ret < 0) + { + printf("main: ERROR: Failed to get termios for %s: %s\n", g_ttydev, strerror(errno)); + close(fd); + return 1; + } + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag &= ~OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + + ret = tcsetattr(fd, TCSANOW, &tty); + if (ret < 0) + { + printf("main: ERROR: Failed to set termios for %s: %s\n", g_ttydev, strerror(errno)); + close(fd); + return 1; + } + + /* Wait for and/or send messages -- forever */ + + for (;;) + { + /* Test IN messages (device-to-host) */ + +#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY + printf("main: Reading from the serial driver\n"); + printf("main: ... (Control-C to terminate) ...\n"); + nbytes = read(fd, g_iobuffer, BUFFER_SIZE-1); + if (nbytes < 0) + { + printf("main: ERROR: Failed to read from %s: %s\n", g_ttydev, strerror(errno)); + close(fd); + return 2; + } + else if (nbytes == 0) + { + printf("main: End-of-file encountered\n"); + break; + } + + g_iobuffer[nbytes] = '\0'; + printf("main: Received %d bytes:\n", nbytes); + printf(" \"%s\"\n", g_iobuffer); +#else + printf("main: Waiting...\n"); + sleep(5); +#endif /* CONFIG_EXAMPLES_USBSERIAL_OUTONLY */ + + /* Test OUT messages (host-to-device) */ + +#ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY +#if !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL) && !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG) + count++; + if (count < 5) + { + printf("main: Sending %d bytes..\n", sizeof(g_shortmsg)); + nbytes = write(fd, g_shortmsg, sizeof(g_shortmsg)); + } + else + { + printf("main: Sending %d bytes..\n", sizeof(g_longmsg)); + nbytes = write(fd, g_longmsg, sizeof(g_longmsg)); + count = 0; + } +#elif !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL) + printf("main: Sending %d bytes..\n", sizeof(g_longmsg)); + nbytes = write(fd, g_longmsg, sizeof(g_longmsg)); +#else /* !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG) */ + printf("main: Sending %d bytes..\n", sizeof(g_shortmsg)); + nbytes = write(fd, g_shortmsg, sizeof(g_shortmsg)); +#endif + + /* Test if write was successful */ + + if (nbytes < 0) + { + printf("main: ERROR: Failed to write to %s: %s\n", g_ttydev, strerror(errno)); + close(fd); + return 2; + } + printf("main: %d bytes sent\n", nbytes); +#endif /* CONFIG_EXAMPLES_USBSERIAL_INONLY */ + } + + close(fd); + return 0; +} + diff --git a/apps/examples/usbserial/main.c b/apps/examples/usbserial/main.c new file mode 100644 index 000000000..d7bc4c56a --- /dev/null +++ b/apps/examples/usbserial/main.c @@ -0,0 +1,461 @@ +/**************************************************************************** + * examples/usbserial/main.c + * + * Copyright (C) 2008, 2010-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/usb/usbdev.h> +#include <nuttx/usb/usbdev_trace.h> + +#ifdef CONFIG_CDCSER +# include <nuttx/usb/cdc_serial.h> +#endif + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#if defined(CONFIG_EXAMPLES_USBSERIAL_INONLY) && defined(CONFIG_EXAMPLES_USBSERIAL_OUTONLY) +# error "Cannot define both CONFIG_EXAMPLES_USBSERIAL_INONLY and _OUTONLY" +#endif +#if defined(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL) && defined(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG) +# error "Cannot define both CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL and _ONLYBIG" +#endif + +#if !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG) && !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL) +# ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY +# define COUNTER_NEEDED 1 +# endif +#endif +#ifdef CONFIG_EXAMPLES_USBSERIAL_TRACEINIT +# define TRACE_INIT_BITS (TRACE_INIT_BIT) +#else +# define TRACE_INIT_BITS (0) +#endif + +#define TRACE_ERROR_BITS (TRACE_DEVERROR_BIT|TRACE_CLSERROR_BIT) + +#ifdef CONFIG_EXAMPLES_USBSERIAL_TRACECLASS +# define TRACE_CLASS_BITS (TRACE_CLASS_BIT|TRACE_CLASSAPI_BIT|TRACE_CLASSSTATE_BIT) +#else +# define TRACE_CLASS_BITS (0) +#endif + +#ifdef CONFIG_EXAMPLES_USBSERIAL_TRACETRANSFERS +# define TRACE_TRANSFER_BITS (TRACE_OUTREQQUEUED_BIT|TRACE_INREQQUEUED_BIT|TRACE_READ_BIT|\ + TRACE_WRITE_BIT|TRACE_COMPLETE_BIT) +#else +# define TRACE_TRANSFER_BITS (0) +#endif + +#ifdef CONFIG_EXAMPLES_USBSERIAL_TRACECONTROLLER +# define TRACE_CONTROLLER_BITS (TRACE_EP_BIT|TRACE_DEV_BIT) +#else +# define TRACE_CONTROLLER_BITS (0) +#endif + +#ifdef CONFIG_EXAMPLES_USBSERIAL_TRACEINTERRUPTS +# define TRACE_INTERRUPT_BITS (TRACE_INTENTRY_BIT|TRACE_INTDECODE_BIT|TRACE_INTEXIT_BIT) +#else +# define TRACE_INTERRUPT_BITS (0) +#endif + +#define TRACE_BITSET (TRACE_INIT_BITS|TRACE_ERROR_BITS|TRACE_CLASS_BITS|\ + TRACE_TRANSFER_BITS|TRACE_CONTROLLER_BITS|TRACE_INTERRUPT_BITS) + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# define trmessage lib_lowprintf +# else +# define message(...) printf(__VA_ARGS__) +# define trmessage printf +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# define trmessage lib_lowprintf +# else +# define message printf +# define trmessage printf +# endif +#endif + +#define IOBUFFER_SIZE 256 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_USBSERIAL_ONLYBIG +static const char g_shortmsg[] = "Hello, World!!\n"; +#endif + +#ifndef CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL +static const char g_longmsg[] = + "The Spanish Armada a Speech by Queen Elizabeth I of England\n" + "Addressed to the English army at Tilbury Fort - 1588\n" + "My loving people, we have been persuaded by some, that are careful of our " + "safety, to take heed how we commit ourselves to armed multitudes, for fear " + "of treachery; but I assure you, I do not desire to live to distrust my " + "faithful and loving people.\n" + "Let tyrants fear; I have always so behaved myself that, under God, I have " + "placed my chiefest strength and safeguard in the loyal hearts and good will " + "of my subjects. And therefore I am come amongst you at this time, not as for " + "my recreation or sport, but being resolved, in the midst and heat of the " + "battle, to live or die amongst you all; to lay down, for my God, and for " + "my kingdom, and for my people, my honour and my blood, even the dust.\n" + "I know I have but the body of a weak and feeble woman; but I have the heart " + "of a king, and of a king of England, too; and think foul scorn that Parma " + "or Spain, or any prince of Europe, should dare to invade the borders of my " + "realms: to which, rather than any dishonour should grow by me, I myself will " + "take up arms; I myself will be your general, judge, and rewarder of every " + "one of your virtues in the field.\n" + "I know already, by your forwardness, that you have deserved rewards and " + "crowns; and we do assure you, on the word of a prince, they shall be duly " + "paid you. In the mean my lieutenant general shall be in my stead, than whom " + "never prince commanded a more noble and worthy subject; not doubting by " + "your obedience to my general, by your concord in the camp, and by your " + "valour in the field, we shall shortly have a famous victory over the enemies " + "of my God, of my kingdom, and of my people.\n"; +#endif + +#ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY +static char g_iobuffer[IOBUFFER_SIZE]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_TRACE +static int trace_callback(struct usbtrace_s *trace, void *arg) +{ + usbtrace_trprintf((trprintf_t)trmessage, trace->event, trace->value); + return 0; +} + +static void dumptrace(void) +{ + (void)usbtrace_enumerate(trace_callback, NULL); +} +#else +# define dumptrace() +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ +#ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY + int infd; +#endif +#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY + int outfd; +#endif +#ifdef COUNTER_NEEDED + int count = 0; +#endif + ssize_t nbytes; +#ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY + int i, j, k; +#endif + int ret; + + /* Initialize the USB serial driver */ + + message("user_start: Registering USB serial driver\n"); +#ifdef CONFIG_CDCSER + ret = cdcser_initialize(0); +#else + ret = usbdev_serialinitialize(0); +#endif + if (ret < 0) + { + message("user_start: ERROR: Failed to create the USB serial device: %d\n", -ret); + return 1; + } + message("user_start: Successfully registered the serial driver\n"); + +#if CONFIG_USBDEV_TRACE && CONFIG_USBDEV_TRACE_INITIALIDSET != 0 + /* If USB tracing is enabled and tracing of initial USB events is specified, + * then dump all collected trace data to stdout + */ + + sleep(5); + dumptrace(); +#endif + + /* Then, in any event, configure trace data collection as configured */ + + usbtrace_enable(TRACE_BITSET); + + /* Open the USB serial device for writing (blocking) */ + +#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY + do + { + message("user_start: Opening USB serial driver\n"); + outfd = open("/dev/ttyUSB0", O_WRONLY); + if (outfd < 0) + { + int errcode = errno; + message("user_start: ERROR: Failed to open /dev/ttyUSB0 for writing: %d\n", errcode); + + /* ENOTCONN means that the USB device is not yet connected */ + + if (errcode == ENOTCONN) + { + message("user_start: Not connected. Wait and try again.\n"); + sleep(5); + } + else + { + /* Give up on other errors */ + + message("user_start: Aborting\n"); + return 2; + } + } + + /* If USB tracing is enabled, then dump all collected trace data to stdout */ + + dumptrace(); + } + while (outfd < 0); +#endif + + /* Open the USB serial device for reading (non-blocking) */ + +#ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY +#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY + infd = open("/dev/ttyUSB0", O_RDONLY|O_NONBLOCK); + if (infd < 0) + { + message("user_start: ERROR: Failed to open /dev/ttyUSB0 for reading: %d\n", errno); + close(outfd); + return 3; + } +#else + do + { + infd = open("/dev/ttyUSB0", O_RDONLY|O_NONBLOCK); + if (infd < 0) + { + int errcode = errno; + message("user_start: ERROR: Failed to open /dev/ttyUSB0 for reading: %d\n", errno); + + /* ENOTCONN means that the USB device is not yet connected */ + + if (errcode == ENOTCONN) + { + message("user_start: Not connected. Wait and try again.\n"); + sleep(5); + } + else + { + /* Give up on other errors */ + + message("user_start: Aborting\n"); + return 3; + } + } + + /* If USB tracing is enabled, then dump all collected trace data to stdout */ + + dumptrace(); + } + while (infd < 0); +#endif +#endif + + message("user_start: Successfully opened the serial driver\n"); + + /* Send messages and get responses -- forever */ + + for (;;) + { + /* Test IN (device-to-host) messages */ + +#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY +#if !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG) && !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL) + if (count < 8) + { + message("user_start: Saying hello\n"); + nbytes = write(outfd, g_shortmsg, sizeof(g_shortmsg)); + count++; + } + else + { + message("user_start: Reciting QEI's speech of 1588\n"); + nbytes = write(outfd, g_longmsg, sizeof(g_longmsg)); + count = 0; + } +#elif !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL) + message("user_start: Reciting QEI's speech of 1588\n"); + nbytes = write(outfd, g_longmsg, sizeof(g_longmsg)); +#else /* !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG) */ + message("user_start: Saying hello\n"); + nbytes = write(outfd, g_shortmsg, sizeof(g_shortmsg)); +#endif + + /* Test if the write was successful */ + + if (nbytes < 0) + { + message("user_start: ERROR: write failed: %d\n", errno); +#ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY + close(infd); +#endif + close(outfd); + return 4; + } + message("user_start: %d bytes sent\n", nbytes); +#endif /* CONFIG_EXAMPLES_USBSERIAL_OUTONLY */ + + /* Test OUT (host-to-device) messages */ + +#ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY + /* Poll for incoming messages */ + + message("user_start: Polling for OUT messages\n"); + for (i = 0; i < 5; i++) + { + memset(g_iobuffer, 'X', IOBUFFER_SIZE); + nbytes = read(infd, g_iobuffer, IOBUFFER_SIZE); + if (nbytes < 0) + { + int errorcode = errno; + if (errorcode != EAGAIN) + { + message("user_start: ERROR: read failed: %d\n", errno); + close(infd); +#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY + close(outfd); +#endif + return 6; + } + } + else + { + message("user_start: Received %d bytes:\n", nbytes); + if (nbytes > 0) + { + for (j = 0; j < nbytes; j += 16) + { + message("user_start: %03x: ", j); + for (k = 0; k < 16; k++) + { + if (k == 8) + { + message(" "); + } + if (j+k < nbytes) + { + message("%02x", g_iobuffer[j+k]); + } + else + { + message(" "); + } + } + message(" "); + for (k = 0; k < 16; k++) + { + if (k == 8) + { + message(" "); + } + if (j+k < nbytes) + { + if (g_iobuffer[j+k] >= 0x20 && g_iobuffer[j+k] < 0x7f) + { + message("%c", g_iobuffer[j+k]); + } + else + { + message("."); + } + } + else + { + message(" "); + } + } + message("\n"); + } + } + } + sleep(1); + } +#else /* CONFIG_EXAMPLES_USBSERIAL_INONLY */ + message("user_start: Waiting\n"); + sleep(5); +#endif /* CONFIG_EXAMPLES_USBSERIAL_INONLY */ + + /* If USB tracing is enabled, then dump all collected trace data to stdout */ + + dumptrace(); + } + + /* Won't get here, but if we did this what we would have to do */ + +#ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY + close(infd); +#endif +#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY + close(outfd); +#endif + return 0; +} + diff --git a/apps/examples/usbstorage/Makefile b/apps/examples/usbstorage/Makefile new file mode 100644 index 000000000..98181e0fd --- /dev/null +++ b/apps/examples/usbstorage/Makefile @@ -0,0 +1,111 @@ +############################################################################ +# apps/examples/usbstorage/Makefile +# +# Copyright (C) 2008, 2010-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# USB device mass storage example + +ASRCS = +CSRCS = usbstrg_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# USB storage built-in application info + +APPNAME1 = msconn +PRIORITY1 = SCHED_PRIORITY_DEFAULT +STACKSIZE1 = 2048 + +APPNAME2 = msdis +PRIORITY2 = SCHED_PRIORITY_DEFAULT +STACKSIZE2 = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_USBSTRG_BUILTIN),y) + $(call REGISTER,$(APPNAME1),$(PRIORITY1),$(STACKSIZE1),$(APPNAME1)_main) + $(call REGISTER,$(APPNAME2),$(PRIORITY2),$(STACKSIZE2),$(APPNAME2)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/usbstorage/usbstrg.h b/apps/examples/usbstorage/usbstrg.h new file mode 100644 index 000000000..a179bc054 --- /dev/null +++ b/apps/examples/usbstorage/usbstrg.h @@ -0,0 +1,166 @@ +/**************************************************************************** + * examples/usbstorage/usbstrg.h + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_USBSTORAGE_USBSTRG_H +#define __EXAMPLES_USBSTORAGE_USBSTRG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdlib.h> + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_EXAMPLES_USBSTRG_NLUNS +# define CONFIG_EXAMPLES_USBSTRG_NLUNS 1 +#endif + +#ifndef CONFIG_EXAMPLES_USBSTRG_DEVMINOR1 +# define CONFIG_EXAMPLES_USBSTRG_DEVMINOR1 0 +#endif + +#ifndef CONFIG_EXAMPLES_USBSTRG_DEVPATH1 +# define CONFIG_EXAMPLES_USBSTRG_DEVPATH1 "/dev/mmcsd0" +#endif + +#if CONFIG_EXAMPLES_USBSTRG_NLUNS > 1 +# ifndef CONFIG_EXAMPLES_USBSTRG_DEVMINOR2 +# error "CONFIG_EXAMPLES_USBSTRG_DEVMINOR2 for LUN=2" +# endif +# ifndef CONFIG_EXAMPLES_USBSTRG_DEVPATH2 +# error "CONFIG_EXAMPLES_USBSTRG_DEVPATH2 for LUN=2" +# endif +# if CONFIG_EXAMPLES_USBSTRG_NLUNS > 2 +# ifndef CONFIG_EXAMPLES_USBSTRG_DEVMINOR3 +# error "CONFIG_EXAMPLES_USBSTRG_DEVMINOR2 for LUN=3" +# endif +# ifndef CONFIG_EXAMPLES_USBSTRG_DEVPATH2 +# error "CONFIG_EXAMPLES_USBSTRG_DEVPATH2 for LUN=3" +# endif +# if CONFIG_EXAMPLES_USBSTRG_NLUNS > 3 +# error "CONFIG_EXAMPLES_USBSTRG_NLUNS must be {1,2,3}" +# endif +# endif +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_lowprintf(__VA_ARGS__) +# define msgflush() +# else +# define message(...) printf(__VA_ARGS__) +# define msgflush() fflush(stdout) +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# define msgflush() +# else +# define message printf +# define msgflush() fflush(stdout) +# endif +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* All global variables used by this example are packed into a structure in + * order to avoid name collisions. + */ + +#if defined(CONFIG_EXAMPLES_USBSTRG_BUILTIN) || defined(CONFIG_EXAMPLES_USBSTRG_DEBUGMM) +struct usbstrg_state_s +{ + /* This is the handle that references to this particular USB storage driver + * instance. It is only needed if the USB mass storage device example is + * built using CONFIG_EXAMPLES_USBSTRG_BUILTIN. In this case, the value + * of the driver handle must be remembered between the 'msconn' and 'msdis' + * commands. + */ + +#ifdef CONFIG_EXAMPLES_USBSTRG_BUILTIN + FAR void *mshandle; +#endif + + /* Heap usage samples. These are useful for checking USB storage memory + * usage and for tracking down memoryh leaks. + */ + +#ifdef CONFIG_EXAMPLES_USBSTRG_DEBUGMM + struct mallinfo mmstart; /* Memory usage before the connection */ + struct mallinfo mmprevious; /* The last memory usage sample */ + struct mallinfo mmcurrent; /* The current memory usage sample */ +#endif +}; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* All global variables used by this example are packed into a structure in + * order to avoid name collisions. + */ + +#if defined(CONFIG_EXAMPLES_USBSTRG_BUILTIN) || defined(CONFIG_EXAMPLES_USBSTRG_DEBUGMM) +extern struct usbstrg_state_s g_usbstrg; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usbstrg_archinitialize + * + * Description: + * Perform architecture specific initialization. This function must + * configure the block device to export via USB. This function must be + * provided by architecture-specific logic in order to use this example. + * + ****************************************************************************/ + +extern int usbstrg_archinitialize(void); + +#endif /* __EXAMPLES_USBSTORAGE_USBSTRG_H */ diff --git a/apps/examples/usbstorage/usbstrg_main.c b/apps/examples/usbstorage/usbstrg_main.c new file mode 100644 index 000000000..884a5929a --- /dev/null +++ b/apps/examples/usbstorage/usbstrg_main.c @@ -0,0 +1,596 @@ +/**************************************************************************** + * examples/usbstorage/usbstrg_main.c + * + * Copyright (C) 2008-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <debug.h> + +#include <nuttx/usb/usbdev.h> +#include <nuttx/usb/usbdev_trace.h> + +#include "usbstrg.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_USBSTRG_TRACEINIT +# define TRACE_INIT_BITS (TRACE_INIT_BIT) +#else +# define TRACE_INIT_BITS (0) +#endif + +#define TRACE_ERROR_BITS (TRACE_DEVERROR_BIT|TRACE_CLSERROR_BIT) + +#ifdef CONFIG_EXAMPLES_USBSTRG_TRACECLASS +# define TRACE_CLASS_BITS (TRACE_CLASS_BIT|TRACE_CLASSAPI_BIT|TRACE_CLASSSTATE_BIT) +#else +# define TRACE_CLASS_BITS (0) +#endif + +#ifdef CONFIG_EXAMPLES_USBSTRG_TRACETRANSFERS +# define TRACE_TRANSFER_BITS (TRACE_OUTREQQUEUED_BIT|TRACE_INREQQUEUED_BIT|TRACE_READ_BIT|\ + TRACE_WRITE_BIT|TRACE_COMPLETE_BIT) +#else +# define TRACE_TRANSFER_BITS (0) +#endif + +#ifdef CONFIG_EXAMPLES_USBSTRG_TRACECONTROLLER +# define TRACE_CONTROLLER_BITS (TRACE_EP_BIT|TRACE_DEV_BIT) +#else +# define TRACE_CONTROLLER_BITS (0) +#endif + +#ifdef CONFIG_EXAMPLES_USBSTRG_TRACEINTERRUPTS +# define TRACE_INTERRUPT_BITS (TRACE_INTENTRY_BIT|TRACE_INTDECODE_BIT|TRACE_INTEXIT_BIT) +#else +# define TRACE_INTERRUPT_BITS (0) +#endif + +#define TRACE_BITSET (TRACE_INIT_BITS|TRACE_ERROR_BITS|TRACE_CLASS_BITS|\ + TRACE_TRANSFER_BITS|TRACE_CONTROLLER_BITS|TRACE_INTERRUPT_BITS) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* All global variables used by this example are packed into a structure in + * order to avoid name collisions. + */ + +#if defined(CONFIG_EXAMPLES_USBSTRG_BUILTIN) || defined(CONFIG_EXAMPLES_USBSTRG_DEBUGMM) +struct usbstrg_state_s g_usbstrg; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: show_memory_usage + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_USBSTRG_DEBUGMM +static void show_memory_usage(struct mallinfo *mmbefore, + struct mallinfo *mmafter) +{ + int diff; + + message(" total used free largest\n"); + message("Before:%11d%11d%11d%11d\n", + mmbefore->arena, mmbefore->uordblks, mmbefore->fordblks, mmbefore->mxordblk); + message("After: %11d%11d%11d%11d\n", + mmafter->arena, mmafter->uordblks, mmafter->fordblks, mmafter->mxordblk); + + diff = mmbefore->uordblks - mmafter->uordblks; + if (diff < 0) + { + message("Change:%11d allocated\n", -diff); + } + else if (diff > 0) + { + message("Change:%11d freed\n", diff); + } +} +#else +# define show_memory_usage(mm1, mm2) +#endif + +/**************************************************************************** + * Name: check_test_memory_usage + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_USBSTRG_DEBUGMM +static void check_test_memory_usage(FAR const char *msg) +{ + /* Get the current memory usage */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_usbstrg.mmcurrent = mallinfo(); +#else + (void)mallinfo(&g_usbstrg.mmcurrent); +#endif + + /* Show the change from the previous time */ + + message("\%s:\n", msg); + show_memory_usage(&g_usbstrg.mmprevious, &g_usbstrg.mmcurrent); + + /* Set up for the next test */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_usbstrg.mmprevious = g_usbstrg.mmcurrent; +#else + memcpy(&g_usbstrg.mmprevious, &g_usbstrg.mmcurrent, sizeof(struct mallinfo)); +#endif +} +#else +# define check_test_memory_usage(msg) +#endif + +/**************************************************************************** + * Name: check_test_memory_usage + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_USBSTRG_DEBUGMM +static void final_memory_usage(FAR const char *msg) +{ + /* Get the current memory usage */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + g_usbstrg.mmcurrent = mallinfo(); +#else + (void)mallinfo(&g_usbstrg.mmcurrent); +#endif + + /* Show the change from the previous time */ + + message("\n%s:\n", msg); + show_memory_usage(&g_usbstrg.mmstart, &g_usbstrg.mmcurrent); +} +#else +# define final_memory_usage(msg) +#endif + +/**************************************************************************** + * Name: usbstrg_enumerate + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_TRACE +static int usbstrg_enumerate(struct usbtrace_s *trace, void *arg) +{ + switch (trace->event) + { + case TRACE_DEVINIT: + message("USB controller initialization: %04x\n", trace->value); + break; + + case TRACE_DEVUNINIT: + message("USB controller un-initialization: %04x\n", trace->value); + break; + + case TRACE_DEVREGISTER: + message("usbdev_register(): %04x\n", trace->value); + break; + + case TRACE_DEVUNREGISTER: + message("usbdev_unregister(): %04x\n", trace->value); + break; + + case TRACE_EPCONFIGURE: + message("Endpoint configure(): %04x\n", trace->value); + break; + + case TRACE_EPDISABLE: + message("Endpoint disable(): %04x\n", trace->value); + break; + + case TRACE_EPALLOCREQ: + message("Endpoint allocreq(): %04x\n", trace->value); + break; + + case TRACE_EPFREEREQ: + message("Endpoint freereq(): %04x\n", trace->value); + break; + + case TRACE_EPALLOCBUFFER: + message("Endpoint allocbuffer(): %04x\n", trace->value); + break; + + case TRACE_EPFREEBUFFER: + message("Endpoint freebuffer(): %04x\n", trace->value); + break; + + case TRACE_EPSUBMIT: + message("Endpoint submit(): %04x\n", trace->value); + break; + + case TRACE_EPCANCEL: + message("Endpoint cancel(): %04x\n", trace->value); + break; + + case TRACE_EPSTALL: + message("Endpoint stall(true): %04x\n", trace->value); + break; + + case TRACE_EPRESUME: + message("Endpoint stall(false): %04x\n", trace->value); + break; + + case TRACE_DEVALLOCEP: + message("Device allocep(): %04x\n", trace->value); + break; + + case TRACE_DEVFREEEP: + message("Device freeep(): %04x\n", trace->value); + break; + + case TRACE_DEVGETFRAME: + message("Device getframe(): %04x\n", trace->value); + break; + + case TRACE_DEVWAKEUP: + message("Device wakeup(): %04x\n", trace->value); + break; + + case TRACE_DEVSELFPOWERED: + message("Device selfpowered(): %04x\n", trace->value); + break; + + case TRACE_DEVPULLUP: + message("Device pullup(): %04x\n", trace->value); + break; + + case TRACE_CLASSBIND: + message("Class bind(): %04x\n", trace->value); + break; + + case TRACE_CLASSUNBIND: + message("Class unbind(): %04x\n", trace->value); + break; + + case TRACE_CLASSDISCONNECT: + message("Class disconnect(): %04x\n", trace->value); + break; + + case TRACE_CLASSSETUP: + message("Class setup(): %04x\n", trace->value); + break; + + case TRACE_CLASSSUSPEND: + message("Class suspend(): %04x\n", trace->value); + break; + + case TRACE_CLASSRESUME: + message("Class resume(): %04x\n", trace->value); + break; + + case TRACE_CLASSRDCOMPLETE: + message("Class RD request complete: %04x\n", trace->value); + break; + + case TRACE_CLASSWRCOMPLETE: + message("Class WR request complete: %04x\n", trace->value); + break; + + default: + switch (TRACE_ID(trace->event)) + { + case TRACE_CLASSAPI_ID: /* Other class driver system API calls */ + message("Class API call %d: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_CLASSSTATE_ID: /* Track class driver state changes */ + message("Class state %d: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_INTENTRY_ID: /* Interrupt handler entry */ + message("Interrrupt %d entry: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_INTDECODE_ID: /* Decoded interrupt trace->event */ + message("Interrrupt decode %d: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_INTEXIT_ID: /* Interrupt handler exit */ + message("Interrrupt %d exit: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_OUTREQQUEUED_ID: /* Request queued for OUT endpoint */ + message("EP%d OUT request queued: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_INREQQUEUED_ID: /* Request queued for IN endpoint */ + message("EP%d IN request queued: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_READ_ID: /* Read (OUT) action */ + message("EP%d OUT read: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_WRITE_ID: /* Write (IN) action */ + message("EP%d IN write: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_COMPLETE_ID: /* Request completed */ + message("EP%d request complete: %04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_DEVERROR_ID: /* USB controller driver error event */ + message("Controller error: %02x:%04x\n", TRACE_DATA(trace->event), trace->value); + break; + + case TRACE_CLSERROR_ID: /* USB class driver error event */ + message("Class error: %02x:%04x\n", TRACE_DATA(trace->event), trace->value); + break; + + default: + message("Unrecognized event: %02x:%02x:%04x\n", + TRACE_ID(trace->event) >> 8, TRACE_DATA(trace->event), trace->value); + break; + } + } + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start/msconn_main + * + * Description: + * This is the main program that configures the USB mass storage device + * and exports the LUN(s). If CONFIG_EXAMPLES_USBSTRG_BUILTIN is defined + * in the NuttX configuration, then this program can be executed by + * entering the "msconn" command at the NSH console. + * + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_USBSTRG_BUILTIN +# define MAIN_NAME msconn_main +# define MAIN_NAME_STRING "msconn" +#else +# define MAIN_NAME user_start +# define MAIN_NAME_STRING "user_start" +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + FAR void *handle; + int ret; + + /* If this program is implemented as the NSH 'msconn' command, then we need to + * do a little error checking to assure that we are not being called re-entrantly. + */ + +#ifdef CONFIG_EXAMPLES_USBSTRG_BUILTIN + + /* Check if there is a non-NULL USB mass storage device handle (meaning that the + * USB mass storage device is already configured). + */ + + if (g_usbstrg.mshandle) + { + message(MAIN_NAME_STRING ": ERROR: Already connected\n"); + return 1; + } +#endif + +#ifdef CONFIG_EXAMPLES_USBSTRG_DEBUGMM +# ifdef CONFIG_CAN_PASS_STRUCTS + g_usbstrg.mmstart = mallinfo(); + g_usbstrg.mmprevious = g_usbstrg.mmstart; +# else + (void)mallinfo(&g_usbstrg.mmstart); + memcpy(&g_usbstrg.mmprevious, &g_usbstrg.mmstart, sizeof(struct mallinfo)); +# endif +#endif + + /* Initialize USB trace output IDs */ + + usbtrace_enable(TRACE_BITSET); + check_test_memory_usage("After usbtrace_enable()"); + + /* Register block drivers (architecture-specific) */ + + message(MAIN_NAME_STRING ": Creating block drivers\n"); + ret = usbstrg_archinitialize(); + if (ret < 0) + { + message(MAIN_NAME_STRING ": usbstrg_archinitialize failed: %d\n", -ret); + return 2; + } + check_test_memory_usage("After usbstrg_archinitialize()"); + + /* Then exports the LUN(s) */ + + message(MAIN_NAME_STRING ": Configuring with NLUNS=%d\n", CONFIG_EXAMPLES_USBSTRG_NLUNS); + ret = usbstrg_configure(CONFIG_EXAMPLES_USBSTRG_NLUNS, &handle); + if (ret < 0) + { + message(MAIN_NAME_STRING ": usbstrg_configure failed: %d\n", -ret); + usbstrg_uninitialize(handle); + return 3; + } + message(MAIN_NAME_STRING ": handle=%p\n", handle); + check_test_memory_usage("After usbstrg_configure()"); + + message(MAIN_NAME_STRING ": Bind LUN=0 to %s\n", CONFIG_EXAMPLES_USBSTRG_DEVPATH1); + ret = usbstrg_bindlun(handle, CONFIG_EXAMPLES_USBSTRG_DEVPATH1, 0, 0, 0, false); + if (ret < 0) + { + message(MAIN_NAME_STRING ": usbstrg_bindlun failed for LUN 1 using %s: %d\n", + CONFIG_EXAMPLES_USBSTRG_DEVPATH1, -ret); + usbstrg_uninitialize(handle); + return 4; + } + check_test_memory_usage("After usbstrg_bindlun()"); + +#if CONFIG_EXAMPLES_USBSTRG_NLUNS > 1 + + message(MAIN_NAME_STRING ": Bind LUN=1 to %s\n", CONFIG_EXAMPLES_USBSTRG_DEVPATH2); + ret = usbstrg_bindlun(handle, CONFIG_EXAMPLES_USBSTRG_DEVPATH2, 1, 0, 0, false); + if (ret < 0) + { + message(MAIN_NAME_STRING ": usbstrg_bindlun failed for LUN 2 using %s: %d\n", + CONFIG_EXAMPLES_USBSTRG_DEVPATH2, -ret); + usbstrg_uninitialize(handle); + return 5; + } + check_test_memory_usage("After usbstrg_bindlun() #2"); + +#if CONFIG_EXAMPLES_USBSTRG_NLUNS > 2 + + message(MAIN_NAME_STRING ": Bind LUN=2 to %s\n", CONFIG_EXAMPLES_USBSTRG_DEVPATH3); + ret = usbstrg_bindlun(handle, CONFIG_EXAMPLES_USBSTRG_DEVPATH3, 2, 0, 0, false); + if (ret < 0) + { + message(MAIN_NAME_STRING ": usbstrg_bindlun failed for LUN 3 using %s: %d\n", + CONFIG_EXAMPLES_USBSTRG_DEVPATH3, -ret); + usbstrg_uninitialize(handle); + return 6; + } + check_test_memory_usage("After usbstrg_bindlun() #3"); + +#endif +#endif + + ret = usbstrg_exportluns(handle); + if (ret < 0) + { + message(MAIN_NAME_STRING ": usbstrg_exportluns failed: %d\n", -ret); + usbstrg_uninitialize(handle); + return 7; + } + check_test_memory_usage("After usbstrg_exportluns()"); + + /* It this program was configued as an NSH command, then just exit now. + * Also, if signals are not enabled (and, hence, sleep() is not supported. + * then we have not real option but to exit now. + */ + +#if !defined(CONFIG_EXAMPLES_USBSTRG_BUILTIN) && !defined(CONFIG_DISABLE_SIGNALS) + + /* Otherwise, this thread will hang around and monitor the USB storage activity */ + + for (;;) + { + msgflush(); + sleep(5); + +# ifdef CONFIG_USBDEV_TRACE + message("\nuser_start: USB TRACE DATA:\n"); + ret = usbtrace_enumerate(usbstrg_enumerate, NULL); + if (ret < 0) + { + message(MAIN_NAME_STRING ": usbtrace_enumerate failed: %d\n", -ret); + usbstrg_uninitialize(handle); + return 8; + } + check_test_memory_usage("After usbtrace_enumerate()"); +# else + message(MAIN_NAME_STRING ": Still alive\n"); +# endif + } +#elif defined(CONFIG_EXAMPLES_USBSTRG_BUILTIN) + + /* Return the USB mass storage device handle so it can be used by the 'misconn' + * command. + */ + + message(MAIN_NAME_STRING ": Connected\n"); + g_usbstrg.mshandle = handle; + check_test_memory_usage("After MS connection"); + +#else /* defined(CONFIG_DISABLE_SIGNALS) */ + + /* Just exit */ + + message(MAIN_NAME_STRING ": Exiting\n"); + + /* Dump debug memory usage */ + + final_memory_usage("Final memory usage"); +#endif + return 0; +} + +/**************************************************************************** + * msdis_main + * + * Description: + * This is a program entry point that will disconnet the USB mass storage + * device. This program is only available if CONFIG_EXAMPLES_USBSTRG_BUILTIN + * is defined in the NuttX configuration. In that case, this program can + * be executed by entering the "msdis" command at the NSH console. + * + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_USBSTRG_BUILTIN +int msdis_main(int argc, char *argv[]) +{ + /* First check if the USB mass storage device is already connected */ + + if (!g_usbstrg.mshandle) + { + message("msdis: ERROR: Not connected\n"); + return 1; + } + check_test_memory_usage("Since MS connection"); + + /* Then disconnect the device and uninitialize the USB mass storage driver */ + + usbstrg_uninitialize(g_usbstrg.mshandle); + g_usbstrg.mshandle = NULL; + message("msdis: Disconnected\n"); + check_test_memory_usage("After usbstrg_uninitialize()"); + + /* Dump debug memory usage */ + + final_memory_usage("Final memory usage"); + return 0; +} +#endif diff --git a/apps/examples/usbterm/Makefile b/apps/examples/usbterm/Makefile new file mode 100644 index 000000000..fe9b77fb8 --- /dev/null +++ b/apps/examples/usbterm/Makefile @@ -0,0 +1,106 @@ +############################################################################ +# apps/examples/usbterm/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# USB terminal example + +ASRCS = +CSRCS = usbterm_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Built-in application info + +APPNAME = usbterm +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: +ifeq ($(CONFIG_EXAMPLES_UBSTERM_BUILTIN),y) + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ +endif + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/usbterm/usbterm.h b/apps/examples/usbterm/usbterm.h new file mode 100644 index 000000000..97ccf5405 --- /dev/null +++ b/apps/examples/usbterm/usbterm.h @@ -0,0 +1,148 @@ +/**************************************************************************** + * examples/usbterm/usbterm.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_USBTERM_USBTERM_H +#define __APPS_EXAMPLES_USBTERM_USBTERM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <semaphore.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_EXAMPLES_USBTERM_BUFLEN +# define CONFIG_EXAMPLES_USBTERM_BUFLEN 256 +#endif + +#ifdef CONFIG_EXAMPLES_USBTERM_TRACEINIT +# define TRACE_INIT_BITS (TRACE_INIT_BIT) +#else +# define TRACE_INIT_BITS (0) +#endif + +#define TRACE_ERROR_BITS (TRACE_DEVERROR_BIT|TRACE_CLSERROR_BIT) + +#ifdef CONFIG_EXAMPLES_USBTERM_TRACECLASS +# define TRACE_CLASS_BITS (TRACE_CLASS_BIT|TRACE_CLASSAPI_BIT|TRACE_CLASSSTATE_BIT) +#else +# define TRACE_CLASS_BITS (0) +#endif + +#ifdef CONFIG_EXAMPLES_USBTERM_TRACETRANSFERS +# define TRACE_TRANSFER_BITS (TRACE_OUTREQQUEUED_BIT|TRACE_INREQQUEUED_BIT|TRACE_READ_BIT|\ + TRACE_WRITE_BIT|TRACE_COMPLETE_BIT) +#else +# define TRACE_TRANSFER_BITS (0) +#endif + +#ifdef CONFIG_EXAMPLES_USBTERM_TRACECONTROLLER +# define TRACE_CONTROLLER_BITS (TRACE_EP_BIT|TRACE_DEV_BIT) +#else +# define TRACE_CONTROLLER_BITS (0) +#endif + +#ifdef CONFIG_EXAMPLES_USBTERM_TRACEINTERRUPTS +# define TRACE_INTERRUPT_BITS (TRACE_INTENTRY_BIT|TRACE_INTDECODE_BIT|TRACE_INTEXIT_BIT) +#else +# define TRACE_INTERRUPT_BITS (0) +#endif + +#define TRACE_BITSET (TRACE_INIT_BITS|TRACE_ERROR_BITS|TRACE_CLASS_BITS|\ + TRACE_TRANSFER_BITS|TRACE_CONTROLLER_BITS|TRACE_INTERRUPT_BITS) + +/* Debug ********************************************************************/ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# ifdef CONFIG_DEBUG +# define message(...) lib_rawprintf(__VA_ARGS__) +# define trmessage lib_rawprintf +# else +# define message(...) printf(__VA_ARGS__) +# define trmessage printf +# endif +#else +# ifdef CONFIG_DEBUG +# define message lib_lowprintf +# define trmessage lib_lowprintf +# else +# define message printf +# define trmessage printf +# endif +#endif + +#define IOBUFFER_SIZE 256 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* All USB terminal state data is packaged in a single structure to minimize + * name conflicts with other global symbols -- a poor man's name space. + */ + +struct usbterm_globals_s +{ + FILE *instream; /* Stream for incoming USB data */ + FILE *outstream; /* Stream for outgoing USB data */ + pthread_t listener; /* USB terminal listener thread */ + + /* Buffers for incoming and outgoing data */ + + char inbuffer[CONFIG_EXAMPLES_USBTERM_BUFLEN]; + char outbuffer[CONFIG_EXAMPLES_USBTERM_BUFLEN]; +}; + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/* USB terminal state data */ + +extern struct usbterm_globals_s g_usbterm; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __APPS_EXAMPLES_USBTERM_USBTERM_H */ diff --git a/apps/examples/usbterm/usbterm_main.c b/apps/examples/usbterm/usbterm_main.c new file mode 100644 index 000000000..092fd7a6f --- /dev/null +++ b/apps/examples/usbterm/usbterm_main.c @@ -0,0 +1,315 @@ +/**************************************************************************** + * examples/usbterm/usbterm_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/usb/usbdev.h> +#include <nuttx/usb/usbdev_trace.h> + +#ifdef CONFIG_CDCSER +# include <nuttx/usb/cdc_serial.h> +#endif + +#include "usbterm.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* USB terminal state data */ + +struct usbterm_globals_s g_usbterm; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: trace_callback + * + * Description: + * Callback from USB trace instrumentation. + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_TRACE +static int trace_callback(struct usbtrace_s *trace, void *arg) +{ + usbtrace_trprintf((trprintf_t)trmessage, trace->event, trace->value); + return 0; +} +#endif + +/**************************************************************************** + * Name: dumptrace + * + * Description: + * Dump collected trace data. + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_TRACE +static void dumptrace(void) +{ + (void)usbtrace_enumerate(trace_callback, NULL); +} +#else +# define dumptrace() +#endif + +/**************************************************************************** + * Name: dumptrace + * + * Description: + * Entry point for the listener thread. + * + ****************************************************************************/ + +FAR void *usbterm_listener(FAR void *parameter) +{ + message("usbterm_listener: Waiting for remote input\n"); + for (;;) + { + /* Display the prompt string on the remote USB serial connection */ + + fputs("\rusbterm> ", g_usbterm.outstream); + fflush(g_usbterm.outstream); + + /* Get the next line of input from the remote USB serial connection */ + + if (fgets(g_usbterm.inbuffer, CONFIG_EXAMPLES_USBTERM_BUFLEN, g_usbterm.instream)) + { + /* Echo the line on the local stdout */ + + fputs(g_usbterm.inbuffer, stdout); + + /* Display the prompt string on stdout */ + + fputs("usbterm> ", stdout); + fflush(stdout); + } + + /* If USB tracing is enabled, then dump all collected trace data to stdout */ + + dumptrace(); + } + + /* Won't get here */ + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: term_main/user_start + * + * Description: + * Main entry point for the USB serial terminal example. + * + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_USBTERM_BUILTIN +# define MAIN_NAME term_main +# define MAIN_STRING "usbterm_main: " +#else +# define MAIN_NAME user_start +# define MAIN_STRING "user_start: " +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + pthread_attr_t attr; + int ret; + + /* Initialize the USB serial driver */ + + message(MAIN_STRING "Registering USB serial driver\n"); +#ifdef CONFIG_CDCSER + ret = cdcser_initialize(0); +#else + ret = usbdev_serialinitialize(0); +#endif + if (ret < 0) + { + message(MAIN_STRING "ERROR: Failed to create the USB serial device: %d\n", -ret); + goto errout; + } + message(MAIN_STRING "Successfully registered the serial driver\n"); + +#if CONFIG_USBDEV_TRACE && CONFIG_USBDEV_TRACE_INITIALIDSET != 0 + /* If USB tracing is enabled and tracing of initial USB events is specified, + * then dump all collected trace data to stdout + */ + + sleep(5); + dumptrace(); +#endif + + /* Then, in any event, configure trace data collection as configured */ + + usbtrace_enable(TRACE_BITSET); + + /* Open the USB serial device for writing */ + + do + { + message(MAIN_STRING "Opening USB serial driver\n"); + + g_usbterm.outstream = fopen("/dev/ttyUSB0", "w"); + if (g_usbterm.outstream == NULL) + { + int errcode = errno; + message(MAIN_STRING "ERROR: Failed to open /dev/ttyUSB0 for writing: %d\n", + errcode); + + /* ENOTCONN means that the USB device is not yet connected */ + + if (errcode == ENOTCONN) + { + message(MAIN_STRING " Not connected. Wait and try again.\n"); + sleep(5); + } + else + { + /* Give up on other errors */ + + goto errout; + } + } + + /* If USB tracing is enabled, then dump all collected trace data to stdout */ + + dumptrace(); + } + while (g_usbterm.outstream == NULL); + + /* Open the USB serial device for reading. Since we are already connected, this + * should not fail. + */ + + g_usbterm.instream = fopen("/dev/ttyUSB0", "r"); + if (g_usbterm.instream == NULL) + { + message(MAIN_STRING "ERROR: Failed to open /dev/ttyUSB0 for reading: %d\n", errno); + goto errout_with_outstream; + } + + message(MAIN_STRING "Successfully opened the serial driver\n"); + + /* Start the USB term listener thread */ + + message(MAIN_STRING "Starting the listener thread\n"); + + ret = pthread_attr_init(&attr); + if (ret != OK) + { + message(MAIN_STRING "pthread_attr_init failed: %d\n", ret); + goto errout_with_streams; + } + + ret = pthread_create(&g_usbterm.listener, &attr, + usbterm_listener, (pthread_addr_t)0); + if (ret != 0) + { + message(MAIN_STRING "Error in thread creation: %d\n", ret); + goto errout_with_streams; + } + + /* Send messages and get responses -- forever */ + + message(MAIN_STRING "Waiting for local input\n"); + for (;;) + { + /* Display the prompt string on stdout */ + + fputs("usbterm> ", stdout); + fflush(stdout); + + /* Get the next line of input from stdin */ + + if (fgets(g_usbterm.outbuffer, CONFIG_EXAMPLES_USBTERM_BUFLEN, stdin)) + { + /* Send the line of input via USB */ + + fputs(g_usbterm.outbuffer, g_usbterm.outstream); + + /* Display the prompt string on the remote USB serial connection */ + + fputs("\rusbterm> ", g_usbterm.outstream); + fflush(g_usbterm.outstream); + } + + /* If USB tracing is enabled, then dump all collected trace data to stdout */ + + dumptrace(); + } + + /* Error exits */ + +errout_with_streams: + fclose(g_usbterm.instream); +errout_with_outstream: + fclose(g_usbterm.outstream); +errout: + message(MAIN_STRING " Aborting\n"); + return 1; +} + diff --git a/apps/examples/wget/Makefile b/apps/examples/wget/Makefile new file mode 100644 index 000000000..4141cc832 --- /dev/null +++ b/apps/examples/wget/Makefile @@ -0,0 +1,95 @@ +############################################################################ +# apps/examples/wget/Makefile +# +# Copyright (C) 2009-2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# wget webclient example + +ASRCS = +CSRCS = target.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + @$(MAKE) -f Makefile.host clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/wget/Makefile.host b/apps/examples/wget/Makefile.host new file mode 100644 index 000000000..fd891afec --- /dev/null +++ b/apps/examples/wget/Makefile.host @@ -0,0 +1,77 @@ +############################################################################ +# apps/examples/wget/Makefile.host +# +# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +WD = ${shell pwd} +TOPDIR = $(WD)/../.. +-include $(TOPDIR)/Make.defs + +OBJS = host.o1 webclient.o1 uip_parsehttpurl.o1 +BIN = wget + +HOSTCFLAGS += -DCONFIG_WEBCLIENT_HOST=1 +HOSTCFLAGS += -I. -include hostdefs.h +VPATH = $(TOPDIR)/netutils/webclient:$(TOPDIR)/netutils/uiplib:. + +all: $(BIN) +.PHONY: clean context clean_context distclean + +$(OBJS): %.o1: %.c + $(HOSTCC) -c $(HOSTCFLAGS) $< -o $@ + +apps/netutils: + @mkdir -p apps/netutils + +apps/netutils/webclient.h: apps/netutils $(TOPDIR)/include/apps/netutils/webclient.h + @cp -a $(TOPDIR)/include/apps/netutils/webclient.h apps/netutils/. + +apps/netutils/uiplib.h: apps/netutils $(TOPDIR)/include/apps/netutils/uiplib.h + @cp -a $(TOPDIR)/include/apps/netutils/uiplib.h apps/netutils/. + +nuttx: + @mkdir nuttx + +nuttx/config.h: nuttx + @touch nuttx/config.h + +headers: apps/netutils/webclient.h apps/netutils/uiplib.h nuttx/config.h + +$(BIN): headers $(OBJS) + $(HOSTCC) $(HOSTLDFLAGS) $(OBJS) -o $@ + +clean: + @rm -f $(BIN).* *.o1 *~ + @rm -rf net nuttx + + diff --git a/apps/examples/wget/host.c b/apps/examples/wget/host.c new file mode 100644 index 000000000..a7b416db5 --- /dev/null +++ b/apps/examples/wget/host.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * examples/wget/host.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <apps/netutils/webclient.h> + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: callback + ****************************************************************************/ + +static void callback(FAR char **buffer, int offset, int datend, + FAR int *buflen, FAR void *arg) +{ + (void)write(1, &((*buffer)[offset]), datend - offset); +} + +/**************************************************************************** + * Name: show_usage + ****************************************************************************/ + +static void show_usage(const char *progname, int exitcode) +{ + fprintf(stderr, "USAGE: %s <url>\n", progname); + exit(exitcode); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/**************************************************************************** + * Name: main + ****************************************************************************/ + +int main(int argc, char **argv, char **envp) +{ + char buffer[1024]; + int ret; + + if (argc != 2) + { + show_usage(argv[0], 1); + } + + printf("WGET: Getting %s\n", argv[1]); + ret = wget(argv[1], buffer, 1024, callback, NULL); + if (ret < 0) + { + fprintf(stderr, "WGET: wget failed: %s\n", strerror(errno)); + } + return 0; +} diff --git a/apps/examples/wget/hostdefs.h b/apps/examples/wget/hostdefs.h new file mode 100755 index 000000000..da072d560 --- /dev/null +++ b/apps/examples/wget/hostdefs.h @@ -0,0 +1,69 @@ +/****************************************************************************
+ * examples/wget/hostdefs.c
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __HOSTDEFS_H
+#define __HOSTDEFS_H
+
+/****************************************************************************
+ * Included Files
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+/****************************************************************************
+ * Preprocessor Defintiions
+ *****************************************************************************/
+
+#define HTONS(a) htons(a)
+#define HTONL(a) htonl(a)
+#define CONFIG_CPP_HAVE_WARNING 1
+#define CONFIG_HAVE_GETHOSTBYNAME 1
+#define FAR
+
+#define ndbg(...) printf(__VA_ARGS__)
+#define nvdbg(...) printf(__VA_ARGS__)
+
+#define ERROR (-1)
+#define OK (0)
+
+/****************************************************************************
+ * Type Definitions
+ *****************************************************************************/
+
+typedef void *(*pthread_startroutine_t)(void *);
+
+#endif /* __HOSTDEFS_H */
diff --git a/apps/examples/wget/target.c b/apps/examples/wget/target.c new file mode 100644 index 000000000..9c55746b3 --- /dev/null +++ b/apps/examples/wget/target.c @@ -0,0 +1,150 @@ +/**************************************************************************** + * examples/wget/target.c + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <unistd.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> + +#include <net/uip/uip.h> + +#include <apps/netutils/uiplib.h> +#include <apps/netutils/resolv.h> +#include <apps/netutils/webclient.h> + +/**************************************************************************** + * Preprocessor Definitions + ****************************************************************************/ + +/* Configuation Checks ******************************************************/ +/* BEWARE: + * There are other configuration settings needed in netutitls/wget/wgetc.s, + * but there are default values for those so we cannot check them here. + */ + +#ifndef CONFIG_EXAMPLE_WGET_IPADDR +# error "You must define CONFIG_EXAMPLE_WGET_IPADDR" +#endif + +#ifndef CONFIG_EXAMPLE_WGET_DRIPADDR +# error "You must define CONFIG_EXAMPLE_WGET_DRIPADDR" +#endif + +#ifndef CONFIG_EXAMPLE_WGET_NETMASK +# error "You must define CONFIG_EXAMPLE_WGET_NETMASK" +#endif + +#ifndef CONFIG_NET +# error "You must define CONFIG_NET" +#endif + +#ifndef CONFIG_NET_TCP +# error "You must define CONFIG_NET_TCP" +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static char g_iobuffer[512]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/**************************************************************************** + * Name: callback + ****************************************************************************/ + +static void callback(FAR char **buffer, int offset, int datend, + FAR int *buflen, FAR void *arg) +{ + (void)write(1, &((*buffer)[offset]), datend - offset); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + struct in_addr addr; +#if defined(CONFIG_EXAMPLE_WGET_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif + +/* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_EXAMPLE_WGET_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_WGET_IPADDR); + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_WGET_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_WGET_NETMASK); + uip_setnetmask("eth0", &addr); + + /* Then start the server */ + + wget(CONFIG_EXAMPLE_WGET_URL, g_iobuffer, 512, callback, NULL); + return 0; +} diff --git a/apps/examples/wlan/Makefile b/apps/examples/wlan/Makefile new file mode 100755 index 000000000..621d9a0aa --- /dev/null +++ b/apps/examples/wlan/Makefile @@ -0,0 +1,95 @@ +############################################################################ +# apps/examples/wlan/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Authors: Gregory Nutt <spudmonkey@racsa.co.cr> +# Rafael Noronha <rafael@pdsolucoes.com.br> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# WLAN Test + +ASRCS = +CSRCS = wlan_main.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/examples/wlan/wlan_main.c b/apps/examples/wlan/wlan_main.c new file mode 100755 index 000000000..04210909a --- /dev/null +++ b/apps/examples/wlan/wlan_main.c @@ -0,0 +1,306 @@ +/**************************************************************************** + * examples/wlan/wlan_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt <spudmonkey@racsa.co.cr> + * Rafael Noronha <rafael@pdsolucoes.com.br> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sched.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/usb/usbhost.h> + +#include <net/if.h> +#include <net/uip/uip.h> +#include <net/uip/uip-arp.h> + +#include <apps/netutils/uiplib.h> + +/* DHCPC may be used in conjunction with any other feature (or not) */ + +#ifdef CONFIG_EXAMPLE_WLAN_DHCPC +# include <arpa/inet.h> +# include <apps/netutils/resolv.h> +# include <apps/netutils/dhcpc.h> +#endif + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +/* Sanity checking */ + +#ifndef CONFIG_USBHOST +# error "CONFIG_USBHOST is not defined" +#endif + +#ifdef CONFIG_USBHOST_BULK_DISABLE +# error "Bulk endpoints are disabled (CONFIG_USBHOST_BULK_DISABLE)" +#endif + +#ifndef CONFIG_NFILE_DESCRIPTORS +# error "CONFIG_NFILE_DESCRIPTORS > 0 needed" +#endif + +/* Provide some default values for other configuration settings */ + +#ifndef CONFIG_EXAMPLES_WLAN_DEFPRIO +# define CONFIG_EXAMPLES_WLAN_DEFPRIO 50 +#endif + +#ifndef CONFIG_EXAMPLES_WLAN_STACKSIZE +# define CONFIG_EXAMPLES_WLAN_STACKSIZE 1024 +#endif + +#ifndef CONFIG_EXAMPLES_WLAN_DEVNAME +# define CONFIG_EXAMPLES_WLAN_DEVNAME "wlan0" +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct usbhost_driver_s *g_drvr; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: wlan_bringup + * + * Description: + * Wait for USB devices to be connected. + * + ****************************************************************************/ + +static inline void wlan_bringup(void) +{ +#if defined(CONFIG_EXAMPLE_WLAN_DHCPC) || defined(CONFIG_EXAMPLE_WLAN_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif + struct in_addr addr; +#ifdef CONFIG_EXAMPLE_WLAN_DHCPC + void *handle; +#endif + + /* Many embedded network interfaces must have a software assigned + * MAC + */ + +#ifdef CONFIG_EXAMPLE_WLAN_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_WLAN_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_EXAMPLE_WLAN_NETMASK); + uip_setnetmask("eth0", &addr); + + /* Set up our host address */ + +#ifdef CONFIG_EXAMPLE_WLAN_DHCPC + addr.s_addr = 0; +#else + addr.s_addr = HTONL(CONFIG_EXAMPLE_WLAN_IPADDR); +#endif + uip_sethostaddr("eth0", &addr); + +#ifdef CONFIG_EXAMPLE_WLAN_DHCPC + /* Set up the resolver */ + + resolv_init(); + + /* Get the MAC address of the NIC */ + + uip_getmacaddr("eth0", mac); + + /* Set up the DHCPC modules */ + + handle = dhcpc_open(&mac, IFHWADDRLEN); + + /* Get an IP address. Note: there is no logic here for renewing + * the address in this example. The address should be renewed in + * ds.lease_time/2 seconds. + */ + + printf("Getting IP address\n"); + if (handle) + { + struct dhcpc_state ds; + (void)dhcpc_request(handle, &ds); + uip_sethostaddr("eth1", &ds.ipaddr); + if (ds.netmask.s_addr != 0) + { + uip_setnetmask("eth0", &ds.netmask); + } + if (ds.default_router.s_addr != 0) + { + uip_setdraddr("eth0", &ds.default_router); + } + if (ds.dnsaddr.s_addr != 0) + { + resolv_conf(&ds.dnsaddr); + } + dhcpc_close(handle); + printf("IP: %s\n", inet_ntoa(ds.ipaddr)); + } +#endif +} + +/**************************************************************************** + * Name: wlan_waiter + * + * Description: + * Wait for USB devices to be connected. + * + ****************************************************************************/ + +static int wlan_waiter(int argc, char *argv[]) +{ + bool connected = false; + int ret; + + printf("wlan_waiter: Running\n"); + for (;;) + { + /* Wait for the device to change state */ + + ret = DRVR_WAIT(g_drvr, connected); + DEBUGASSERT(ret == OK); + + connected = !connected; + printf("wlan_waiter: %s\n", connected ? "connected" : "disconnected"); + + /* Did we just become connected? */ + + if (connected) + { + /* Yes.. enumerate the newly connected device */ + + ret = DRVR_ENUMERATE(g_drvr); + + /* If the enumeration was successful, then bring up the interface */ + + wlan_bringup(); + } + } + + /* Keep the compiler from complaining */ + + return 0; +} + +/**************************************************************************** + * Name: user_start + ****************************************************************************/ + +int user_start(int argc, char *argv[]) +{ + pid_t pid; + int ret; + + /* First, register all of the USB host Wireless LAN drivers */ + + printf("user_start: Register drivers\n"); + ret = usbhost_wlaninit(); + if (ret != OK) + { + printf("user_start: Failed to register the WLAN driver\n"); + } + + /* Then get an instance of the USB host interface */ + + printf("user_start: Initialize USB host WLAN driver\n"); + g_drvr = usbhost_initialize(0); + if (g_drvr) + { + /* Start a thread to handle device connection. */ + + printf("user_start: Start wlan_waiter\n"); + +#ifndef CONFIG_CUSTOM_STACK + pid = task_create("usbhost", CONFIG_EXAMPLES_WLAN_DEFPRIO, + CONFIG_EXAMPLES_WLAN_STACKSIZE, + (main_t)wlan_waiter, (const char **)NULL); +#else + pid = task_create("usbhost", CONFIG_EXAMPLES_WLAN_DEFPRIO, + (main_t)wlan_waiter, (const char **)NULL); +#endif + + /* Now just sleep. Eventually logic here will perform the device test. */ + + for (;;) + { + sleep(5); + printf("usert_start: Still alive\n"); + } + } + return 0; +} diff --git a/apps/graphics/Makefile b/apps/graphics/Makefile new file mode 100644 index 000000000..01775a2e3 --- /dev/null +++ b/apps/graphics/Makefile @@ -0,0 +1,72 @@ +############################################################################ +# apps/graphics/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration + +# Sub-directories + +SUBDIRS = tiff + +# Sub-directories that might need context setup + +CNTXTDIRS = + +all: nothing +.PHONY: nothing context depend clean distclean + +nothing: + +context: + @for dir in $(CNTXTDIRS) ; do \ + $(MAKE) -C $$dir context TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +depend: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir depend TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +clean: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +distclean: clean + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir distclean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +-include Make.dep + diff --git a/apps/graphics/tiff/Makefile b/apps/graphics/tiff/Makefile new file mode 100644 index 000000000..617717c65 --- /dev/null +++ b/apps/graphics/tiff/Makefile @@ -0,0 +1,93 @@ +############################################################################ +# apps/graphics/tiff/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NuttX TIFF Creation Tool + +ASRCS = +CSRCS = tiff_addstrip.c tiff_finalize.c tiff_initialize.c tiff_utils.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/graphics/tiff/README.txt b/apps/graphics/tiff/README.txt new file mode 100644 index 000000000..b414107ff --- /dev/null +++ b/apps/graphics/tiff/README.txt @@ -0,0 +1,15 @@ +README for the TIFF Creation Library +===================================== + +This directory contains a library that can be used to create TIFF image +files. This file was created for the purpose of supporting screen dumps +from an LCD. Howeve, the logic is general and could be used for most +any purpose. + +The only usage documentation is in the (rather extensive) comments in +the file apps/include/tiff.h + +Unit Test +========= + +See apps/examples/tiff diff --git a/apps/graphics/tiff/tiff_addstrip.c b/apps/graphics/tiff/tiff_addstrip.c new file mode 100644 index 000000000..fa2a50e72 --- /dev/null +++ b/apps/graphics/tiff/tiff_addstrip.c @@ -0,0 +1,239 @@ +/**************************************************************************** + * apps/graphics/tiff/tiff_addstrip.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <apps/tiff.h> + +#include "tiff_internal.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiff_addstrip + * + * Description: + * Convert an RGB565 strip to an RGB888 strip and write it to tmpfile2. + * + * Add an image data strip. The size of the strip in pixels must be equal + * to the RowsPerStrip x ImageWidth values that were provided to + * tiff_initialize(). + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state instance. + * buffer - A buffer containing a single row of data. + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ +int tiff_convstrip(FAR struct tiff_info_s *info, FAR const uint8_t *strip) +{ +#ifdef CONFIG_DEBUG_GRAPHICS + size_t ntotal; +#endif + size_t nbytes; + FAR uint16_t *src; + FAR uint8_t *dest; + uint16_t rgb565; + int ret; + int i; + + DEBUGASSERT(info->iobuffer != NULL); + + /* Convert each RGB565 pixel to RGB888 */ + + src = (FAR uint16_t *)strip; + dest = info->iobuffer; + nbytes = 0; +#ifdef CONFIG_DEBUG_GRAPHICS + ntotal = 0; +#endif + + for (i = 0; i < info->pps; i++) + { + /* Convert RGB565 to RGB888 */ + + rgb565 = *src++; + *dest++ = (rgb565 >> (11-3)) & 0xf8; /* Move bits 11-15 to 3-7 */ + *dest++ = (rgb565 >> ( 5-2)) & 0xfc; /* Move bits 5-10 to 2-7 */ + *dest++ = (rgb565 << ( 3)) & 0xf8; /* Move bits 0- 4 to 3-7 */ + + /* Update the byte count */ + + nbytes += 3; +#ifdef CONFIG_DEBUG_GRAPHICS + ntotal += 3; +#endif + + /* Flush the conversion buffer to tmpfile2 when it becomes full */ + + if (nbytes > (info->iosize-3)) + { + ret = tiff_write(info->tmp2fd, info->iobuffer, nbytes); + if (ret < 0) + { + return ret; + } + + /* Reset to refill the conversion buffer */ + + dest = info->iobuffer; + nbytes = 0; + } + } + + /* Flush any buffer data to tmpfile2 */ + + ret = tiff_write(info->tmp2fd, info->iobuffer, nbytes); +#ifdef CONFIG_DEBUG_GRAPHICS + ASSERT(ntotal == info->bps); +#endif + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiff_addstrip + * + * Description: + * Add an image data strip. The size of the strip in pixels must be equal + * to the RowsPerStrip x ImageWidth values that were provided to + * tiff_initialize(). + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state instance. + * buffer - A buffer containing a single row of data. + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +int tiff_addstrip(FAR struct tiff_info_s *info, FAR const uint8_t *strip) +{ + ssize_t newsize; + int ret; + + /* Add the new strip based on the color format. For FB_FMT_RGB16_565, + * will have to perform a conversion to RGB888. + */ + + if (info->colorfmt == FB_FMT_RGB16_565) + { + ret = tiff_convstrip(info, strip); + } + + /* For other formats, it is a simple write using the number of bytes per strip */ + + else + { + ret = tiff_write(info->tmp2fd, strip, info->bps); + } + + if (ret < 0) + { + goto errout; + } + + /* Write the byte count to the outfile and the offset to tmpfile1 */ + + ret = tiff_putint32(info->outfd, info->bps); + if (ret < 0) + { + goto errout; + } + info->outsize += 4; + + ret = tiff_putint32(info->tmp1fd, info->tmp2size); + if (ret < 0) + { + goto errout; + } + info->tmp1size += 4; + + /* Increment the size of tmp2file. */ + + info->tmp2size += info->bps; + + /* Pad tmpfile2 as necessary achieve word alignment */ + + newsize = tiff_wordalign(info->tmp2fd, info->tmp2size); + if (newsize < 0) + { + ret = (int)newsize; + goto errout; + } + info->tmp2size = (size_t)newsize; + + /* Increment the number of strips in the TIFF file */ + + info->nstrips++; + return OK; + +errout: + tiff_abort(info); + return ret; +} + diff --git a/apps/graphics/tiff/tiff_finalize.c b/apps/graphics/tiff/tiff_finalize.c new file mode 100644 index 000000000..0d7a222a5 --- /dev/null +++ b/apps/graphics/tiff/tiff_finalize.c @@ -0,0 +1,439 @@ +/**************************************************************************** + * apps/graphics/tiff/tiff_finalize.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <unistd.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <apps/tiff.h> + +#include "tiff_internal.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiff_readifdentry + * + * Description: + * Read the IFD entry at the specified offset. + * + * Input Parameters: + * fd - File descriptor to rad from + * offset - Offset to read from + * ifdentry - Location to read the data + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +static int tiff_readifdentry(int fd, off_t offset, + FAR struct tiff_ifdentry_s *ifdentry) +{ + off_t newoffs; + ssize_t nbytes; + + /* Seek to the read position */ + + newoffs = lseek(fd, offset, SEEK_SET); + if (newoffs == (off_t)-1) + { + return -errno; + } + + /* Then read the IFD entry. Anything returned by tiff_read other than the + * size of the IFD entry would be an error. + */ + + nbytes = tiff_read(fd, ifdentry, SIZEOF_IFD_ENTRY); + return nbytes == SIZEOF_IFD_ENTRY ? OK : -ENOSPC; +} + +/**************************************************************************** + * Name: tiff_writeifdentry + * + * Description: + * Write the IFD entry at the specified offset. + * + * Input Parameters: + * fd - File descriptor to rad from + * offset - Offset to read from + * ifdentry - Location to read the data + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +static int tiff_writeifdentry(int fd, off_t offset, + FAR struct tiff_ifdentry_s *ifdentry) +{ + off_t newoffs; + + /* Seek to the write position */ + + newoffs = lseek(fd, offset, SEEK_SET); + if (newoffs == (off_t)-1) + { + return -errno; + } + + /* Then write the IFD entry */ + + return tiff_write(fd, ifdentry, SIZEOF_IFD_ENTRY); +} + +/**************************************************************************** + * Name: tiff_cleanup + * + * Description: + * Normal clean-up after completion of the TIFF file creation + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF + * state instance. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void tiff_cleanup(FAR struct tiff_info_s *info) +{ + /* Close all opened files */ + + if (info->outfd >= 0) + { + (void)close(info->outfd); + } + info->outfd = -1; + + if (info->tmp1fd >= 0) + { + (void)close(info->tmp1fd); + } + info->tmp1fd = -1; + + if (info->tmp2fd >= 0) + { + (void)close(info->tmp2fd); + } + info->tmp2fd = -1; + + /* And remove the temporary files */ + + (void)unlink(info->tmpfile1); + (void)unlink(info->tmpfile2); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiff_finalize + * + * Description: + * Finalize the TIFF output file, completing the TIFF file creation steps. + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state + * instance. + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +int tiff_finalize(FAR struct tiff_info_s *info) +{ + struct tiff_ifdentry_s ifdentry; + FAR uint8_t *ptr; + size_t maxoffsets; +#ifdef CONFIG_DEBUG_GRAPHICS + size_t total; +#endif + off_t offset; + int ret; + int i; + int j; + + /* Put all of the pieces together to create the final output file. There + * are three pieces: + * + * 1) outfile: The partial output file containing the header, IFD and strip + * counts. This includes the StripOffsets and StripByteCounts that need + * to be updated. Size=outsize; + * 2) tmpfile1: This contains the offsets into tmpfile3 for each strip. The + * size of this file is tmp1size. These offsets are relative to the + * beginning of tmpfile3 and need to be offset by outsize+tmp1size. + * 3) tmpfile3: The strip data. Size is tmp2size. This is raw image data; + * no fixups are required. + */ + + DEBUGASSERT(info && info->outfd >= 0 && info->tmp1fd >= 0 && info->tmp2fd >= 0); + DEBUGASSERT((info->outsize & 3) == 0 && (info->tmp1size & 3) == 0); + + /* Fix-up the count value in the StripByteCounts IFD entry in the outfile. + * The actual number of strips was unknown at the time that the IFD entry + * was written. + */ + + ret = tiff_readifdentry(info->outfd, info->filefmt->sbcifdoffset, &ifdentry); + if (ret < 0) + { + goto errout; + } + + tiff_put32(ifdentry.count, info->nstrips); + + ret = tiff_writeifdentry(info->outfd, info->filefmt->sbcifdoffset, &ifdentry); + if (ret < 0) + { + goto errout; + } + + /* Fix-up the count and offset values in the StripOffsets IFD entry in the + * outfile. The StripOffsets data will be stored immediately after the + * outfile, hence, the correct offset is outsize. + */ + + ret = tiff_readifdentry(info->outfd, info->filefmt->soifdoffset, &ifdentry); + if (ret < 0) + { + goto errout; + } + + tiff_put32(ifdentry.count, info->nstrips); + tiff_put32(ifdentry.offset, info->outsize); + + ret = tiff_writeifdentry(info->outfd, info->filefmt->soifdoffset, &ifdentry); + if (ret < 0) + { + goto errout; + } + + /* Rewind to the beginning of tmpfile1 */ + + offset = lseek(info->tmp1fd, 0, SEEK_SET); + if (offset == (off_t)-1) + { + ret = -errno; + goto errout; + } + + /* Seek to the end of the outfile */ + + ret = lseek(info->outfd, 0, SEEK_END); + if (offset == (off_t)-1) + { + ret = -errno; + goto errout; + } + + /* Now read strip offset data from tmpfile1, update the offsets, and write + * the updated offsets to the outfile. The strip data will begin at offset + * outsize + tmp1size; + */ + + maxoffsets = info->iosize >> 2; +#ifdef CONFIG_DEBUG_GRAPHICS + total = 0; +#endif + + for (i = 0; i < info->nstrips; ) + { + size_t noffsets; + ssize_t nbytes; + + /* Read a group of up to 32-bit values */ + + noffsets = info->nstrips - i; + if (noffsets > maxoffsets) + { + noffsets = maxoffsets; + } + + nbytes = tiff_read(info->tmp1fd, info->iobuffer, noffsets << 2); + + /* If an error occurs or we fail to read exactly this number of + * bytes, then something bad happened. + */ + + if (nbytes != noffsets << 2) + { + goto errout; + } + + /* Fix up the offsets */ + + for (j = 0, ptr = info->iobuffer; + j < noffsets; + j++, ptr += 4) + { + uint32_t stripoff = tiff_get32(ptr); + stripoff += (info->outsize + info->tmp1size); + tiff_put32(ptr, stripoff); + } + + /* Then write the corrected offsets to the outfile */ + + ret = tiff_write(info->outfd, info->iobuffer, nbytes); + if (ret < 0) + { + goto errout; + } + + /* Update the count of offsets written */ + + i += noffsets; +#ifdef CONFIG_DEBUG_GRAPHICS + total += nbytes; +#endif + } +#ifdef CONFIG_DEBUG_GRAPHICS + ASSERT(total == info->tmp1size); +#endif + + /* Rewind to the beginning of tmpfile2 */ + + offset = lseek(info->tmp2fd, 0, SEEK_SET); + if (offset == (off_t)-1) + { + ret = -errno; + goto errout; + } + + /* Finally, copy the tmpfile2 to the end of the outfile */ + +#ifdef CONFIG_DEBUG_GRAPHICS + total = 0; +#endif + for (;;) + { + ssize_t nbytes; + + /* Read a block of data from tmpfile2 */ + + nbytes = tiff_read(info->tmp2fd, info->iobuffer, info->iosize); + + /* Check for tead errors and for end-of-file */ + + if (nbytes < 0) + { + ret = (int)nbytes; + goto errout; + } + else if (nbytes == 0) + { + break; + } + + /* Then copy the data to the outfile */ + + ret = tiff_write(info->outfd, info->iobuffer, nbytes); + if (ret < 0) + { + goto errout; + } + +#ifdef CONFIG_DEBUG_GRAPHICS + total += nbytes; +#endif + } +#ifdef CONFIG_DEBUG_GRAPHICS + ASSERT(total == info->tmp2size); +#endif + + /* Close all files and return success */ + + tiff_cleanup(info); + return OK; + +errout: + tiff_abort(info); + return ret; +} + +/************************************************************************************ + * Name: tiff_abort + * + * Description: + * Abort the TIFF file creation and create-up resources. + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state instance. + * + * Returned Value: + * None + * + ************************************************************************************/ + +void tiff_abort(FAR struct tiff_info_s *info) +{ + /* Perform normal cleanup */ + + tiff_cleanup(info); + + /* But then delete the output file as well */ + + (void)unlink(info->outfile); +} + diff --git a/apps/graphics/tiff/tiff_initialize.c b/apps/graphics/tiff/tiff_initialize.c new file mode 100644 index 000000000..0e5b3229c --- /dev/null +++ b/apps/graphics/tiff/tiff_initialize.c @@ -0,0 +1,910 @@ +/**************************************************************************** + * apps/graphics/tiff/tiff_initialize.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <apps/tiff.h> + +#include "tiff_internal.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ +/* Bi-level Images + * + * Offset Description Contents/Notes + * Header: 0 Byte Order "II" or "MM" + * 2 Magic Number 42 + * 4 1st IFD offset 10 + * 8 [2 bytes padding] + * IFD: 10 Number of Directory Entries 13 + * 12 NewSubfileType + * 24 ImageWidth Number of columns is a user parameter + * 36 ImageLength Number of rows is a user parameter + * 48 Compression Hard-coded no compression (for now) + * 60 PhotometricInterpretation Value is a user parameter + * 72 StripOffsets Offset and count determined as strips added + * 84 RowsPerStrip Value is a user parameter + * 96 StripByteCounts Offset and count determined as strips added + * 108 XResolution Value is a user parameter + * 120 YResolution Value is a user parameter + * 132 Resolution Unit Hard-coded to "inches" + * 144 Software + * 156 DateTime + * 168 Next IFD offset 0 + * 170 [2 bytes padding] + * Values: + * 172 XResolution Hard-coded to 300/1 + * 180 YResolution Hard-coded to 300/1 + * 188 "NuttX" Length = 6 (including NUL terminator) + * 194 "YYYY:MM:DD HH:MM:SS" Length = 20 (ncluding NUL terminator) + * 214 [2 bytes padding] + * 216 StripByteCounts Beginning of strip byte counts + * xxx StripOffsets Beginning of strip offsets + * xxx [Probably padding] + * xxx Data for strips Beginning of strip data + */ + +#define TIFF_IFD_OFFSET (SIZEOF_TIFF_HEADER+2) + +#define TIFF_BILEV_NIFDENTRIES 13 +#define TIFF_BILEV_STRIPIFDOFFS 72 +#define TIFF_BILEV_STRIPBCIFDOFFS 96 +#define TIFF_BILEV_VALOFFSET 172 +#define TIFF_BILEV_XRESOFFSET 172 +#define TIFF_BILEV_YRESOFFSET 180 +#define TIFF_BILEV_SWOFFSET 188 +#define TIFF_BILEV_DATEOFFSET 194 +#define TIFF_BILEV_STRIPBCOFFSET 216 + +#define TIFF_SOFTWARE_STRING "NuttX" +#define TIFF_SOFTWARE_STRLEN 6 + +#define TIFF_DATETIME_FORMAT "%Y:%m:%d %H:%M:%S" +#define TIFF_DATETIME_STRLEN 20 + +/* Greyscale Images have one additional IFD entry: BitsPerSample (4 or 8) + * + * Header: 0 Byte Order "II" or "MM" + * 2 Magic Number 42 + * 4 1st IFD offset 10 + * 8 [2 bytes padding] + * IFD: 10 Number of Directory Entries 14 + * 12 NewSubfileType + * 24 ImageWidth Number of columns is a user parameter + * 36 ImageLength Number of rows is a user parameter + * 48 BitsPerSample + * 60 Compression Hard-coded no compression (for now) + * 72 PhotometricInterpretation Value is a user parameter + * 84 StripOffsets Offset and count determined as strips added + * 96 RowsPerStrip Value is a user parameter + * 108 StripByteCounts Offset and count determined as strips added + * 120 XResolution Value is a user parameter + * 132 YResolution Value is a user parameter + * 144 Resolution Unit Hard-coded to "inches" + * 156 Software + * 168 DateTime + * 180 Next IFD offset 0 + * 182 [2 bytes padding] + * Values: + * 184 XResolution Hard-coded to 300/1 + * 192 YResolution Hard-coded to 300/1 + * 200 "NuttX" Length = 6 (including NUL terminator) + * 206 "YYYY:MM:DD HH:MM:SS" Length = 20 (ncluding NUL terminator) + * 226 [2 bytes padding] + * 228 StripByteCounts Beginning of strip byte counts + * xxx StripOffsets Beginning of strip offsets + * xxx [Probably padding] + * xxx Data for strips Beginning of strip data + */ + +#define TIFF_GREY_NIFDENTRIES 14 +#define TIFF_GREY_STRIPIFDOFFS 84 +#define TIFF_GREY_STRIPBCIFDOFFS 108 +#define TIFF_GREY_VALOFFSET 184 +#define TIFF_GREY_XRESOFFSET 184 +#define TIFF_GREY_YRESOFFSET 192 +#define TIFF_GREY_SWOFFSET 200 +#define TIFF_GREY_DATEOFFSET 206 +#define TIFF_GREY_STRIPBCOFFSET 228 + +/* RGB Images have two additional IFD entries: BitsPerSample (8,8,8) and + * SamplesPerPixel (3): + * + * Header: 0 Byte Order "II" or "MM" + * 2 Magic Number 42 + * 4 1st IFD offset 10 + * 8 [2 bytes padding] + * IFD: 10 Number of Directory Entries 15 + * 12 NewSubfileType + * 24 ImageWidth Number of columns is a user parameter + * 36 ImageLength Number of rows is a user parameter + * 48 BitsPerSample 8, 8, 8 + * 60 Compression Hard-coded no compression (for now) + * 72 PhotometricInterpretation Value is a user parameter + * 84 StripOffsets Offset and count determined as strips added + * 96 SamplesPerPixel Hard-coded to 3 + * 108 RowsPerStrip Value is a user parameter + * 120 StripByteCounts Offset and count determined as strips added + * 132 XResolution Value is a user parameter + * 144 YResolution Value is a user parameter + * 156 Resolution Unit Hard-coded to "inches" + * 168 Software + * 180 DateTime + * 192 Next IFD offset 0 + * 194 [2 bytes padding] + * Values: + * 196 XResolution Hard-coded to 300/1 + * 204 YResolution Hard-coded to 300/1 + * 212 BitsPerSample 8, 8, 8 + * 218 [2 bytes padding] + * 220 "NuttX" Length = 6 (including NUL terminator) + * 226 "YYYY:MM:DD HH:MM:SS" Length = 20 (ncluding NUL terminator) + * 246 [2 bytes padding] + * 248 StripByteCounts Beginning of strip byte counts + * xxx StripOffsets Beginning of strip offsets + * xxx [Probably padding] + * xxx Data for strips Beginning of strip data + */ + +#define TIFF_RGB_NIFDENTRIES 15 +#define TIFF_RGB_STRIPIFDOFFS 84 +#define TIFF_RGB_STRIPBCIFDOFFS 120 +#define TIFF_RGB_VALOFFSET 196 +#define TIFF_RGB_XRESOFFSET 196 +#define TIFF_RGB_YRESOFFSET 204 +#define TIFF_RGB_BPSOFFSET 212 +#define TIFF_RGB_SWOFFSET 220 +#define TIFF_RGB_DATEOFFSET 226 +#define TIFF_RGB_STRIPBCOFFSET 248 + +/* Debug *******************************************************************/ +/* CONFIG_DEBUG_TIFFOFFSETS may be defined (along with CONFIG_DEBUG and + * CONFIG_DEBUG_GRAPHICS) in order to verify the pre-determined TIFF file + * offsets. + */ + +#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_GRAPHICS) +# undef CONFIG_DEBUG_TIFFOFFSETS +#endif + +#ifdef CONFIG_DEBUG_TIFFOFFSETS +# define tiff_offset(o,l) (o) += (l) +# define tiff_checkoffs(o,x) ASSERT((o) == (x)) +#else +# define tiff_offset(o,l) +# define tiff_checkoffs(o,x) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct tiff_filefmt_s g_bilevinfo = +{ + TIFF_BILEV_NIFDENTRIES, /* nifdentries, Number of IFD entries */ + TIFF_BILEV_STRIPIFDOFFS, /* soifdoffset, Offset to StripOffset IFD entry */ + TIFF_BILEV_STRIPBCIFDOFFS, /* sbcifdoffset, Offset to StripByteCount IFD entry */ + TIFF_BILEV_VALOFFSET, /* valoffset, Offset to first values */ + TIFF_BILEV_XRESOFFSET, /* xresoffset, Offset to XResolution values */ + TIFF_BILEV_YRESOFFSET, /* yresoffset, Offset to yResolution values */ + TIFF_BILEV_SWOFFSET, /* swoffset, Offset to Software string */ + TIFF_BILEV_DATEOFFSET, /* dateoffset, Offset to DateTime string */ + TIFF_BILEV_STRIPBCOFFSET /* sbcoffset, Offset to StripByteCount values */ +}; + +static const struct tiff_filefmt_s g_greyinfo = +{ + TIFF_GREY_NIFDENTRIES, /* nifdentries, Number of IFD entries */ + TIFF_GREY_STRIPIFDOFFS, /* soifdoffset, Offset to StripOffset IFD entry */ + TIFF_GREY_STRIPBCIFDOFFS, /* sbcifdoffset, Offset to StripByteCount IFD entry */ + TIFF_GREY_VALOFFSET, /* valoffset, Offset to first values */ + TIFF_GREY_XRESOFFSET, /* xresoffset, Offset to XResolution values */ + TIFF_GREY_YRESOFFSET, /* yresoffset, Offset to yResolution values */ + TIFF_GREY_SWOFFSET, /* swoffset, Offset to Software string */ + TIFF_GREY_DATEOFFSET, /* dateoffset, Offset to DateTime string */ + TIFF_GREY_STRIPBCOFFSET /* sbcoffset, Offset to StripByteCount values */ +}; + +static const struct tiff_filefmt_s g_rgbinfo = +{ + TIFF_RGB_NIFDENTRIES, /* nifdentries, Number of IFD entries */ + TIFF_RGB_STRIPIFDOFFS, /* soifdoffset, Offset to StripOffset IFD entry */ + TIFF_RGB_STRIPBCIFDOFFS, /* sbcifdoffset, Offset to StripByteCount IFD entry */ + TIFF_RGB_VALOFFSET, /* valoffset, Offset to first values */ + TIFF_RGB_XRESOFFSET, /* xresoffset, Offset to XResolution values */ + TIFF_RGB_YRESOFFSET, /* yresoffset, Offset to yResolution values */ + TIFF_RGB_SWOFFSET, /* swoffset, Offset to Software string */ + TIFF_RGB_DATEOFFSET, /* dateoffset, Offset to DateTime string */ + TIFF_RGB_STRIPBCOFFSET /* sbcoffset, Offset to StripByteCount values */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiff_putheader + * + * Description: + * Setup to create a new TIFF file. + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state + * instance. + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +static inline int tiff_putheader(FAR struct tiff_info_s *info) +{ + struct tiff_header_s hdr; + int ret; + + /* 0-1: Byte order */ + +#ifdef CONFIG_ENDIAN_BIG + hdr.order[0] = 'M'; /* "MM"=big endian */ + hdr.order[1] = 'M'; +#else + hdr.order[0] = 'I'; /* "II"=little endian */ + hdr.order[1] = 'I'; +#endif + + /* 2-3: 42 in appropriate byte order */ + + tiff_put16(hdr.magic, 42); + + /* 4-7: Offset to the first IFD */ + + tiff_put32(hdr.offset, TIFF_IFD_OFFSET); + + /* Write the header to the output file */ + + ret = tiff_write(info->outfd, &hdr, SIZEOF_TIFF_HEADER); + if (ret != OK) + { + return ret; + } + + /* Two pad bytes following the header */ + + ret = tiff_putint16(info->outfd, 0); + return ret; +} + +/**************************************************************************** + * Name: tiff_putifdentry + * + * Description: + * Write an IFD entry to outfile + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state + * instance. + * tag - The value for the IFD tag field + * type - The value for the IFD type field + * count - The value for the IFD count field + * offset - The value for the IFD offset field + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +static int tiff_putifdentry(FAR struct tiff_info_s *info, uint16_t tag, + uint16_t type, uint32_t count, uint32_t offset) +{ + struct tiff_ifdentry_s ifd; + tiff_put16(ifd.tag, tag); + tiff_put16(ifd.type, type); + tiff_put32(ifd.count, count); + tiff_put32(ifd.offset, offset); + return tiff_write(info->outfd, &ifd, SIZEOF_IFD_ENTRY); +} + +/**************************************************************************** + * Name: tiff_putifdentry + * + * Description: + * Write an IFD with a 16-bit immediate value + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state + * instance. + * tag - The value for the IFD tag field + * type - The value for the IFD type field + * count - The value for the IFD count field + * value - The 16-bit immediate value + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +static int tiff_putifdentry16(FAR struct tiff_info_s *info, uint16_t tag, + uint16_t type, uint32_t count, uint16_t value) +{ + union + { + uint8_t b[4]; + uint32_t w; + } u; + + u.w = 0; + tiff_put16(u.b, value); + return tiff_putifdentry(info, tag, type, count, u.w); +} + +/**************************************************************************** + * Name: tiff_datetime + * + * Description: + * Get the DateTime string + * + * Input Parameters: + * + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +static int tiff_datetime(FAR char *timbuf, unsigned int buflen) +{ + struct timespec ts; + struct tm tm; + int ret; + + /* Get the current time */ + + ret = clock_gettime(CLOCK_REALTIME, &ts); + if (ret < 0) + { + gdbg("clock_gettime failed: %d\n", errno); + return ERROR; + } + + /* Break the current time up into the format needed by strftime */ + + (void)gmtime_r((FAR const time_t*)&ts.tv_sec, &tm); + + /* Comvert the current time in the TIFF format */ + + (void)strftime(timbuf, buflen, TIFF_DATETIME_FORMAT, &tm); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiff_initialize + * + * Description: + * Setup to create a new TIFF file. + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state instance. + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +int tiff_initialize(FAR struct tiff_info_s *info) +{ + uint16_t val16; +#if CONFIG_DEBUG_TIFFOFFSETS + off_t offset = 0; +#endif + char timbuf[TIFF_DATETIME_STRLEN + 8]; + int ret = -EINVAL; + + DEBUGASSERT(info && info->outfile && info->tmpfile1 && info->tmpfile2); + + /* Open all output files */ + + info->outfd = open(info->outfile, O_RDWR|O_CREAT|O_TRUNC, 0666); + if (info->outfd < 0) + { + gdbg("Failed to open %s for reading/writing: %d\n", info->outfile, errno); + goto errout; + } + + info->tmp1fd = open(info->tmpfile1, O_RDWR|O_CREAT|O_TRUNC, 0666); + if (info->tmp1fd < 0) + { + gdbg("Failed to open %s for reading/writing: %d\n", info->tmpfile1, errno); + goto errout; + } + + info->tmp2fd = open(info->tmpfile1, O_RDWR|O_CREAT|O_TRUNC, 0666); + if (info->tmp2fd < 0) + { + gdbg("Failed to open %s for reading/writing: %d\n", info->tmpfile1, errno); + goto errout; + } + + /* Make some decisions using the color format. Only the following are + * supported: + */ + + info->pps = info->imgwidth * info->rps; /* Pixels per strip */ + switch (info->colorfmt) + { + case FB_FMT_Y1: /* BPP=1, monochrome, 0=black */ + info->filefmt = &g_bilevinfo; /* Bi-level file image file info */ + info->imgflags = IMGFLAGS_FMT_Y1; /* Bit encoded image characteristics */ + info->bps = (info->pps + 7) >> 3; /* Bytes per strip */ + break; + + case FB_FMT_Y4: /* BPP=4, 4-bit greyscale, 0=black */ + info->filefmt = &g_greyinfo; /* Greyscale file image file info */ + info->imgflags = IMGFLAGS_FMT_Y4; /* Bit encoded image characteristics */ + info->bps = (info->pps + 1) >> 1; /* Bytes per strip */ + break; + + case FB_FMT_Y8: /* BPP=8, 8-bit greyscale, 0=black */ + info->filefmt = &g_greyinfo; /* Greyscale file image file info */ + info->imgflags = IMGFLAGS_FMT_Y8; /* Bit encoded image characteristics */ + info->bps = info->pps; /* Bytes per strip */ + break; + + case FB_FMT_RGB16_565: /* BPP=16 R=6, G=6, B=5 */ + info->filefmt = &g_rgbinfo; /* RGB file image file info */ + info->imgflags = IMGFLAGS_FMT_RGB16_565; /* Bit encoded image characteristics */ + info->bps = 3 * info->pps; /* Bytes per strip */ + break; + + case FB_FMT_RGB24: /* BPP=24 R=8, G=8, B=8 */ + info->filefmt = &g_rgbinfo; /* RGB file image file info */ + info->imgflags = IMGFLAGS_FMT_RGB24; /* Bit encoded image characteristics */ + info->bps = 3 *info->pps; /* Bytes per strip */ + break; + + default: + gdbg("Unsupported color format: %d\n", info->colorfmt); + return -EINVAL; + } + + /* Write the TIFF header data to the outfile: + * + * Header: 0 Byte Order "II" or "MM" + * 2 Magic Number 42 + * 4 1st IFD offset 10 + * 8 [2 bytes padding] + */ + + ret = tiff_putheader(info); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, TIFF_IFD_OFFSET); + + /* Write the Number of directory entries + * + * All formats: Offset 10 Number of Directory Entries 12 + */ + + ret = tiff_putint16(info->outfd, info->filefmt->nifdentries); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, 2); + + /* Write the NewSubfileType IFD entry + * + * All formats: Offset 12 NewSubfileType + */ + + ret = tiff_putifdentry16(info, IFD_TAG_NEWSUBFILETYPE, IFD_FIELD_LONG, 1, 0); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + + /* Write ImageWidth and ImageLength + * + * All formats: Offset 24 ImageWidth Number of columns is a user parameter + * 36 ImageLength Number of rows is a user parameter + */ + + ret = tiff_putifdentry16(info, IFD_TAG_IMAGEWIDTH, IFD_FIELD_SHORT, 1, info->imgwidth); + if (ret == OK) + { + ret= tiff_putifdentry16(info, IFD_TAG_IMAGELENGTH, IFD_FIELD_SHORT, 1, info->imgheight); + } + + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, 2*SIZEOF_IFD_ENTRY); + + /* Write BitsPerSample + * + * Bi-level Images: None + * Greyscale: Offset 48 BitsPerSample (4 or 8) + * RGB: Offset 48 BitsPerSample (8,8,8) + */ + + tiff_checkoffs(offset, 48); + if (IMGFLAGS_ISGREY(info->imgflags)) + { + if (IMGFLAGS_ISGREY8(info->imgflags)) + { + val16 = 8; + } + else + { + val16 = 4; + } + + ret = tiff_putifdentry16(info, IFD_TAG_BITSPERSAMPLE, IFD_FIELD_SHORT, 1, val16); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + } + else if (IMGFLAGS_ISRGB(info->imgflags)) + { + ret = tiff_putifdentry(info, IFD_TAG_BITSPERSAMPLE, IFD_FIELD_SHORT, 3, TIFF_RGB_BPSOFFSET); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + } + + /* Write Compression: + * + * Bi-level Images: Offset 48 Hard-coded no compression (for now) + * Greyscale: Offset 60 " " " " "" " " " " " " + * RGB: Offset 60 " " " " "" " " " " " " + */ + + ret = tiff_putifdentry16(info, IFD_TAG_COMPRESSION, IFD_FIELD_SHORT, 1, TAG_COMP_NONE); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + + /* Write PhotometricInterpretation: + * + * Bi-level Images: Offset 48 Hard-coded BlackIsZero + * Greyscale: Offset 72 Hard-coded BlackIsZero + * RGB: Offset 72 Hard-coded RGB + */ + + if (IMGFLAGS_ISRGB(info->imgflags)) + { + val16 = TAG_PMI_RGB; + } + else + { + val16 = TAG_PMI_BLACK; + } + + ret = tiff_putifdentry16(info, IFD_TAG_PMI, IFD_FIELD_SHORT, 1, val16); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + + /* Write StripOffsets: + * + * Bi-level Images: Offset 72 Value determined by switch statement above + * Greyscale: Offset 84 Value determined by switch statement above + * RGB: Offset 84 Value determined by switch statement above + */ + + tiff_checkoffs(offset, info->filefmt->soifdoffset); + ret = tiff_putifdentry(info, IFD_TAG_STRIPOFFSETS, IFD_FIELD_LONG, 0, 0); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + + /* Write SamplesPerPixel + * + * Bi-level Images: N/A + * Greyscale: N/A + * RGB: Offset 96 Hard-coded to 3 + */ + + if (IMGFLAGS_ISRGB(info->imgflags)) + { + ret = tiff_putifdentry16(info, IFD_TAG_SAMPLESPERPIXEL, IFD_FIELD_SHORT, 1, 3); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + } + + /* Write RowsPerStrip: + * + * Bi-level Images: Offset 84 Value is a user parameter + * Greyscale: Offset 96 Value is a user parameter + * RGB: Offset 108 Value is a user parameter + */ + + ret = tiff_putifdentry16(info, IFD_TAG_ROWSPERSTRIP, IFD_FIELD_SHORT, 1, info->rps); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + + /* Write StripByteCounts: + * + * Bi-level Images: Offset 96 Count determined as strips added, Value offset = 216 + * Greyscale: Offset 108 Count determined as strips added, Value offset = 228 + * RGB: Offset 120 Count determined as strips added, Value offset = 248 + */ + + tiff_checkoffs(offset, info->filefmt->sbcifdoffset); + ret = tiff_putifdentry(info, IFD_TAG_STRIPCOUNTS, IFD_FIELD_LONG, 0, info->filefmt->sbcoffset); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + + /* Write XResolution and YResolution: + * + * Bi-level Images: Offset 108 and 120, Values are a user parameters + * Greyscale: Offset 120 and 132, Values are a user parameters + * RGB: Offset 132 and 144, Values are a user parameters + */ + + ret = tiff_putifdentry(info, IFD_TAG_XRESOLUTION, IFD_FIELD_RATIONAL, 1, info->filefmt->xresoffset); + if (ret == OK) + { + ret = tiff_putifdentry(info, IFD_TAG_YRESOLUTION, IFD_FIELD_RATIONAL, 1, info->filefmt->yresoffset); + } + + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, 2*SIZEOF_IFD_ENTRY); + + /* Write ResolutionUnit: + * + * Bi-level Images: Offset 132, Hard-coded to "inches" + * Greyscale: Offset 144, Hard-coded to "inches" + * RGB: Offset 156, Hard-coded to "inches" + */ + + ret = tiff_putifdentry16(info, IFD_TAG_RESUNIT, IFD_FIELD_SHORT, 1, TAG_RESUNIT_INCH); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + + /* Write Software: + * + * Bi-level Images: Offset 144 Count, Hard-coded "NuttX" + * Greyscale: Offset 156 Count, Hard-coded "NuttX" + * RGB: Offset 168 Count, Hard-coded "NuttX" + */ + + ret = tiff_putifdentry(info, IFD_TAG_SOFTWARE, IFD_FIELD_ASCII, TIFF_SOFTWARE_STRLEN, info->filefmt->swoffset); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + + /* Write DateTime: + * + * Bi-level Images: Offset 156 Count, Format "YYYY:MM:DD HH:MM:SS" + * Greyscale: Offset 168 Count, Format "YYYY:MM:DD HH:MM:SS" + * RGB: Offset 180 Count, Format "YYYY:MM:DD HH:MM:SS" + */ + + ret = tiff_putifdentry(info, IFD_TAG_DATETIME, IFD_FIELD_ASCII, TIFF_DATETIME_STRLEN, info->filefmt->dateoffset); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, SIZEOF_IFD_ENTRY); + + /* Write Next IFD Offset and 2 bytes of padding: + * + * Bi-level Images: Offset 168, Next IFD offset + * Offset 170, [2 bytes padding] + * Greyscale: Offset 180, Next IFD offset + * Offset 182, [2 bytes padding] + * RGB: Offset 192, Next IFD offset + * Offset 194, [2 bytes padding] + */ + + ret = tiff_putint32(info->outfd, 0); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, 4); + + /* Now we begin the value section of the file */ + + tiff_checkoffs(offset, info->filefmt->valoffset); + + /* Write the XResolution and YResolution data: + * + * Bi-level Images: Offset 172 Count, Hard-coded to 300/1 + * Offset 180 Count, Hard-coded to 300/1 + * Greyscale: Offset 184 Count, Hard-coded to 300/1 + * Offset 192 Count, Hard-coded to 300/1 + * RGB: Offset 196 Count, Hard-coded to 300/1 + * Offset 204 Count, Hard-coded to 300/1 + */ + + tiff_checkoffs(offset, info->filefmt->xresoffset); + ret = tiff_putint32(info->outfd, 300); + if (ret == OK) + { + ret = tiff_putint32(info->outfd, 1); + } + + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, 8); + + tiff_checkoffs(offset, info->filefmt->yresoffset); + ret = tiff_putint32(info->outfd, 300); + if (ret == OK) + { + ret = tiff_putint32(info->outfd, 1); + } + + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, 8); + + /* Write RGB BitsPerSample Data: + * + * Bi-level Images: N/A + * Greyscale: N/A + * RGB: Offset 212 BitsPerSample (8,8,8) + * Offset 218 [2 bytes padding] + */ + + if (IMGFLAGS_ISRGB(info->imgflags)) + { + tiff_checkoffs(offset, TIFF_RGB_BPSOFFSET); + tiff_putint16(info->outfd, 8); + tiff_putint16(info->outfd, 8); + tiff_putint16(info->outfd, 8); + tiff_putint16(info->outfd, 0); + tiff_offset(offset, 8); + } + + /* Write the Software string: + * + * + * Bi-level Images: Offset 188, Hard-coded "NuttX" + * Greyscale: Offset 200, Hard-coded "NuttX" + * RGB: Offset 220, Hard-coded "NuttX" + */ + + tiff_checkoffs(offset, info->filefmt->swoffset); + ret = tiff_putstring(info->outfd, TIFF_SOFTWARE_STRING, TIFF_SOFTWARE_STRLEN); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, TIFF_SOFTWARE_STRLEN); + + /* Write the DateTime string: + * + * + * Bi-level Images: Offset 188, Format "YYYY:MM:DD HH:MM:SSS" + * Greyscale: Offset 200, Hard-coded "NuttX" + * RGB: Offset 220, Hard-coded "NuttX" + */ + + tiff_checkoffs(offset, info->filefmt->dateoffset); + ret = tiff_datetime(timbuf, TIFF_DATETIME_STRLEN + 8); + if (ret < 0) + { + goto errout; + } + + ret = tiff_putstring(info->outfd, timbuf, TIFF_DATETIME_STRLEN); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, TIFF_DATETIME_STRLEN); + + /* Add two bytes of padding */ + + ret = tiff_putint16(info->outfd, 0); + if (ret < 0) + { + goto errout; + } + tiff_offset(offset, 2); + + /* And that should do it! */ + + tiff_checkoffs(offset, info->filefmt->sbcoffset); + info->outsize = info->filefmt->sbcoffset; + return OK; + +errout: + tiff_abort(info); + return ret; +} + diff --git a/apps/graphics/tiff/tiff_internal.h b/apps/graphics/tiff/tiff_internal.h new file mode 100644 index 000000000..5596122fa --- /dev/null +++ b/apps/graphics/tiff/tiff_internal.h @@ -0,0 +1,211 @@ +/**************************************************************************** + * apps/graphics/tiff/tiff_internal.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_GRAPHICS_TIFF_TIFF_INTERNAL_H +#define __APPS_GRAPHICS_TIFF_TIFF_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> + +#include <nuttx/nx/nxglib.h> +#include <apps/tiff.h> + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ +/* Image Type ***************************************************************/ + +#define IMGFLAGS_BILEV_BIT (1 << 0) +#define IMGFLAGS_GREY_BIT (1 << 1) +#define IMGFLAGS_GREY8_BIT (1 << 2) +#define IMGFLAGS_RGB_BIT (1 << 3) +#define IMGFLAGS_RGB565_BIT (1 << 4) + +#define IMGFLAGS_FMT_Y1 (IMGFLAGS_BILEV_BIT) +#define IMGFLAGS_FMT_Y4 (IMGFLAGS_GREY_BIT) +#define IMGFLAGS_FMT_Y8 (IMGFLAGS_GREY_BIT|IMGFLAGS_GREY8_BIT) +#define IMGFLAGS_FMT_RGB16_565 (IMGFLAGS_RGB_BIT) +#define IMGFLAGS_FMT_RGB24 (IMGFLAGS_RGB_BIT|IMGFLAGS_RGB565_BIT) + +#define IMGFLAGS_ISBILEV(f) \ + (((f) & IMGFLAGS_BILEV_BIT) != 0) +#define IMGFLAGS_ISGREY(f) \ + (((f) & IMGFLAGS_GREY_BIT) != 0) +#define IMGFLAGS_ISGREY4(f) \ + (((f) & (IMGFLAGS_GREY_BIT|IMGFLAGS_GREY8_BIT)) == IMGFLAGS_GREY_BIT) +#define IMGFLAGS_ISGREY8(f) \ + (((f) & (IMGFLAGS_GREY_BIT|IMGFLAGS_GREY8_BIT)) == (IMGFLAGS_GREY_BIT|IMGFLAGS_GREY8_BIT)) +#define IMGFLAGS_ISRGB(f) \ + (((f) & IMGFLAGS_FMT_RGB24) != 0) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiff_read + * + * Description: + * Read TIFF data from the specified file + * + * Input Parameters: + * fd - Open file descriptor to read from + * buffer - Read-only buffer containing the data to be written + * count - The number of bytes to write + * + * Returned Value: + * On success, then number of bytes read; Zero is returned on EOF. + * Otherwise, a negated errno value on failure. + * + ****************************************************************************/ + +EXTERN ssize_t tiff_read(int fd, FAR void *buffer, size_t count); + +/**************************************************************************** + * Name: tiff_write + * + * Description: + * Write TIFF data to the specified file + * + * Input Parameters: + * fd - Open file descriptor to write to + * buffer - Read-only buffer containing the data to be written + * count - The number of bytes to write + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +EXTERN int tiff_write(int fd, FAR const void *buffer, size_t count); + +/**************************************************************************** + * Name: tiff_putint16 + * + * Description: + * Write two bytes to the outfile. + * + * Input Parameters: + * fd - File descriptor to be used. + * value - The 2-byte, uint16_t value to write + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +EXTERN int tiff_putint16(int fd, uint16_t value); + +/**************************************************************************** + * Name: tiff_putint32 + * + * Description: + * Write four bytes to the outfile. + * + * Input Parameters: + * fd - File descriptor to be used. + * value - The 4-byte, uint32_t value to write + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +EXTERN int tiff_putint32(int fd, uint32_t value); + +/**************************************************************************** + * Name: tiff_putstring + * + * Description: + * Write a string of fixed length to the outfile. + * + * Input Parameters: + * fd - File descriptor to be used. + * string - A pointer to the memory containing the string + * len - The length of the string (including the NUL terminator) + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +EXTERN int tiff_putstring(int fd, FAR const char *string, int len); + +/**************************************************************************** + * Name: tiff_wordalign + * + * Description: + * Pad a file with zeros as necessary to achieve word alignament. + * + * Input Parameters: + * fd - File descriptor to be used. + * size - The current size of the file + * + * Returned Value: + * The new size of the file on success. A negated errno value on failure. + * + ****************************************************************************/ + +EXTERN ssize_t tiff_wordalign(int fd, size_t size); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __APPS_GRAPHICS_TIFF_TIFF_INTERNAL_H */ + diff --git a/apps/graphics/tiff/tiff_utils.c b/apps/graphics/tiff/tiff_utils.c new file mode 100644 index 000000000..c326d0274 --- /dev/null +++ b/apps/graphics/tiff/tiff_utils.c @@ -0,0 +1,381 @@ +/**************************************************************************** + * apps/graphics/tiff/tiff_utils.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <string.h> +#include <unistd.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <apps/tiff.h> + +#include "tiff_internal.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiff_put/get16/32 + * + * Description: + * Put and get 16 and 32 values in the correct byte order at the specified + * position. + * + * Input Parameters: + * dest - The location to store the multi-byte data (put only) + * src - The location to get the multi-byte data (get only) + * value - The value to be stored (put only) + * + * Returned Value: + * None (put) + * The extracted value (get) + * + ****************************************************************************/ + +void tiff_put16(FAR uint8_t *dest, uint16_t value) +{ +#ifdef CONFIG_ENDIAN_BIG + *dest++ = (uint8_t)(value >> 8); + *dest = (uint8_t)(value & 0xff); +#else + *dest++ = (uint8_t)(value & 0xff); + *dest = (uint8_t)(value >> 8); +#endif +} + +void tiff_put32(FAR uint8_t *dest, uint32_t value) +{ +#ifdef CONFIG_ENDIAN_BIG + tiff_put16(dest, (uint16_t)(value >> 16)); + tiff_put16(dest+2, (uint16_t)(value & 0xffff)); +#else + tiff_put16(dest, (uint16_t)(value & 0xffff)); + tiff_put16(dest+2, (uint16_t)(value >> 16)); +#endif +} + +uint16_t tiff_get16(FAR uint8_t *src) +{ +#ifdef CONFIG_ENDIAN_BIG + return (uint16_t)src[0] << 8 | (uint16_t)src[1]; +#else + return (uint16_t)src[1] << 8 | (uint16_t)src[0]; +#endif +} + +uint32_t tiff_get32(FAR uint8_t *src) +{ +#ifdef CONFIG_ENDIAN_BIG + return (uint32_t)tiff_get16(src) << 16 | (uint32_t)tiff_get16(src+2); +#else + return (uint32_t)tiff_get16(src+2) << 16 | (uint32_t)tiff_get16(src); +#endif + +} + +/**************************************************************************** + * Name: tiff_read + * + * Description: + * Read TIFF data from the specified file + * + * Input Parameters: + * fd - Open file descriptor to read from + * buffer - Read-only buffer containing the data to be written + * count - The number of bytes to write + * + * Returned Value: + * On success, then number of bytes read; Zero is returned on EOF. + * Otherwise, a negated errno value on failure. + * + ****************************************************************************/ + +ssize_t tiff_read(int fd, FAR void *buffer, size_t count) +{ + size_t ntotal; + ssize_t nbytes; + int errval; + + /* This loop retries the write until either: (1) it completes successfully, + * or (2) until an irrecoverble error occurs. + */ + + for (ntotal = 0; ntotal < count; ) + { + /* Do the read. The number of bytes left to read is the total + * requested size (count) minus the amount that we have alread read + * (ntotal). + */ + + nbytes = read(fd, buffer, count-ntotal); + + /* Check for an error */ + + if (nbytes < 0) + { + /* EINTR is not an error.. this just means that the write was + * interrupted by a signal. + */ + + errval = errno; + if (errval != EINTR) + { + /* Other errors are bad news and we will break out with an error */ + + return -errval; + } + } + + /* Zero is a special case and means that the end of file was encountered. */ + + else if (nbytes == 0) + { + break; + } + + /* What if read returns some number of bytes other than the requested number? + * This probably means that the end-of-file will be encountered the next time + * that we call read(). + */ + + else + { + buffer += nbytes; + ntotal += nbytes; + } + } + + return ntotal; +} + +/**************************************************************************** + * Name: tiff_write + * + * Description: + * Write TIFF data to the specified file + * + * Input Parameters: + * fd - Open file descriptor to write to + * buffer - Read-only buffer containing the data to be written + * count - The number of bytes to write + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +int tiff_write(int fd, FAR const void *buffer, size_t count) +{ + ssize_t nbytes; + int errval; + + /* This loop retries the write until either: (1) it completes successfully, + * or (2) until an irrecoverble error occurs. + */ + + while (count > 0) + { + /* Do the write */ + + nbytes = write(fd, buffer, count); + + /* Check for an error */ + + if (nbytes < 0) + { + /* EINTR is not an error.. this just means that the write was + * interrupted by a signal. + */ + + errval = errno; + if (errval != EINTR) + { + /* Other errors are bad news and we will break out with an error */ + + return -errval; + } + } + + /* What if write returns some number of bytes other than the requested number? */ + + else + { + DEBUGASSERT(nbytes == count); + buffer += nbytes; + count -= nbytes; + } + } + + return OK; +} + +/**************************************************************************** + * Name: tiff_putint16 + * + * Description: + * Write two bytes to the outfile. + * + * Input Parameters: + * fd - File descriptor to be used. + * value - The 2-byte, uint16_t value to write + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +int tiff_putint16(int fd, uint16_t value) +{ + uint8_t bytes[2]; + + /* Write the two bytes to the output file */ + + tiff_put16(bytes, value); + return tiff_write(fd, bytes, 2); +} + +/**************************************************************************** + * Name: tiff_putint32 + * + * Description: + * Write four bytes to the outfile. + * + * Input Parameters: + * fd - File descriptor to be used. + * value - The 4-byte, uint32_t value to write + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +int tiff_putint32(int fd, uint32_t value) +{ + uint8_t bytes[4]; + + /* Write the four bytes to the output file */ + + tiff_put32(bytes, value); + return tiff_write(fd, bytes, 4); +} + +/**************************************************************************** + * Name: tiff_putstring + * + * Description: + * Write a string of fixed length to the outfile. + * + * Input Parameters: + * fd - File descriptor to be used. + * string - A pointer to the memory containing the string + * len - The length of the string (including the NUL terminator) + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ****************************************************************************/ + +int tiff_putstring(int fd, FAR const char *string, int len) +{ +#ifdef CONFIG_DEBUG_GRAPHICS + int actual = strlen(string); + + ASSERT(len = actual+1); +#endif + return tiff_write(fd, string, len); +} + +/**************************************************************************** + * Name: tiff_wordalign + * + * Description: + * Pad a file with zeros as necessary to achieve word alignament. + * + * Input Parameters: + * fd - File descriptor to be used. + * size - The current size of the file + * + * Returned Value: + * The new size of the file on success. A negated errno value on failure. + * + ****************************************************************************/ + +ssize_t tiff_wordalign(int fd, size_t size) +{ + unsigned int remainder; + int ret; + + remainder = size & 3; + if (remainder > 0) + { + unsigned int nbytes = 4 - remainder; + uint32_t value = 0; + + ret = tiff_write(fd, &value, nbytes); + if (ret < 0) + { + return (ssize_t)ret; + } + size += nbytes; + } + return size; +} diff --git a/apps/include/apps.h b/apps/include/apps.h new file mode 100644 index 000000000..d494500d1 --- /dev/null +++ b/apps/include/apps.h @@ -0,0 +1,148 @@ +/**************************************************************************** + * include/apps/apps.h + * + * Copyright(C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise <uros.platise@isotel.eu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_APPS_APPS_H +#define __INCLUDE_APPS_APPS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <sys/types.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct namedapp_s +{ + const char *name; /* Invocation name and as seen under /sbin/ */ + int priority; /* Use: SCHED_PRIORITY_DEFAULT */ + int stacksize; /* Desired stack size */ + main_t main; /* Entry point: main(int argc, char *argv[]) */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* The "bindir" is file system that supports access to the named applications. + * It is typically mounted under /bin. + */ + +#ifdef CONFIG_APPS_BINDIR +struct mountpt_operations; +extern const struct mountpt_operations binfs_operations; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: namedapp_isavail + * + * Description: + * Checks for availabiliy of application registerred during compile time. + * + * Input Parameter: + * filename - Name of the linked-in binary to be started. + * + * Returned Value: + * This is an end-user function, so it follows the normal convention: + * Returns index of builtin application. If it is not found then it + * returns -1 (ERROR) and sets errno appropriately. + * + ****************************************************************************/ + +EXTERN int namedapp_isavail(FAR const char *appname); + +/**************************************************************************** + * Name: namedapp_getname + * + * Description: + * Returns pointer to a name of built-in application pointed by the + * index. + * + * Input Parameter: + * index, from 0 and on ... + * + * Returned Value: + * Returns valid pointer pointing to the app name if index is valid. + * Otherwise NULL is returned. + * + ****************************************************************************/ + +EXTERN const char *namedapp_getname(int index); + +/**************************************************************************** + * Name: exec_namedapp + * + * Description: + * Executes builtin named application registered during compile time. + * New application is run in a separate task context (and thread). + * + * Input Parameter: + * filename - Name of the linked-in binary to be started. + * argv - Argument list + * + * Returned Value: + * This is an end-user function, so it follows the normal convention: + * Returns the PID of the exec'ed module. On failure, it.returns + * -1 (ERROR) and sets errno appropriately. + * + ****************************************************************************/ + +EXTERN int exec_namedapp(FAR const char *appname, FAR const char **argv); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __INCLUDE_APPS_APPS_H */ diff --git a/apps/include/ftpc.h b/apps/include/ftpc.h new file mode 100644 index 000000000..ed5e3fab9 --- /dev/null +++ b/apps/include/ftpc.h @@ -0,0 +1,224 @@ +/**************************************************************************** + * apps/include/ftpc.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_INCLUDE_FTPC_H +#define __APPS_INCLUDE_FTPC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdbool.h> +#include <signal.h> +#include <time.h> + +#include <netinet/in.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_FTP_DEFTIMEO +# define CONFIG_FTP_DEFTIMEO 30 +#endif + +#ifndef CONFIG_FTP_ANONPWD +# define CONFIG_FTP_ANONPWD "" +#endif + +#ifndef CONFIG_FTP_DEFPORT +# define CONFIG_FTP_DEFPORT 21 +#endif + +#ifndef CONFIG_FTP_MAXREPLY +# define CONFIG_FTP_MAXREPLY 256 +#endif + +#ifndef CONFIG_FTP_TMPDIR +# define CONFIG_FTP_TMPDIR "/tmp" +#endif + +#ifndef CONFIG_FTP_BUFSIZE +# define CONFIG_FTP_BUFSIZE 1024 +#endif + +#ifndef CONFIG_FTP_MAXPATH +# define CONFIG_FTP_MAXPATH 256 +#endif + +#ifndef CONFIG_FTP_SIGNAL +# define CONFIG_FTP_SIGNAL SIGUSR1 +#endif + +/* Interface arguments ******************************************************/ +/* These definitions describe how a put operation should be performed */ + +#define FTPC_PUT_NORMAL 0 /* Just PUT the file on the server */ +#define FTPC_PUT_APPEND 1 /* Append file to an existing file on the server */ +#define FTPC_PUT_UNIQUE 2 /* Create a uniquely named file on the server */ +#define FTPC_PUT_RESUME 3 /* Resume a previously started PUT transfer */ + +/* These definitions describe how a get operation should be performed */ + +#define FTPC_GET_NORMAL 0 /* Just GET the file from the server */ +#define FTPC_GET_APPEND 1 /* Append new file to an existing file */ +#define FTPC_GET_RESUME 3 /* Resume a previously started GET transfer */ + +/* Transfer mode encoding */ + +#define FTPC_XFRMODE_UNKNOWN 0 /* Nothing has been transferred yet */ +#define FTPC_XFRMODE_ASCII 1 /* Last transfer was ASCII mode */ +#define FTPC_XFRMODE_BINARY 2 /* Last transfer was binary mode */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ +/* This "handle" describes the FTP session */ + +typedef FAR void *SESSION; + +/* This structure provides information to connect to a host FTP server. + * + * addr - The IPv4 address of the FTP server (or the proxy) for the FTP + * server. + * port - The port number on the FTP server to connect to (in host byte + * order). This is usually port 21 for FTP. You may set this + * value to zero to let FTPC select the default port number for + * you (it will use CONFIG_FTP_DEFPORT). + */ + +struct ftpc_connect_s +{ + struct in_addr addr; /* Server/proxy IP address */ + uint16_t port; /* Server/proxy port number (usually 21) in network order */ +}; + +/* This structure provides FTP login information */ + +struct ftpc_login_s +{ + FAR const char *uname; /* Login uname */ + FAR const char *pwd; /* Login pwd */ + FAR const char *rdir; /* Initial remote directory */ + bool pasv; /* true: passive connection mode */ +}; + +/* This structure describes one simple directory listing. The directory + * list container as well the individual filename strings are allocated. + * The number of names in tha actual allocated array is variable, given + * by the nnames field. + * + * Since the structure and file names are allocated, they must be freed + * by calling ftpc_dirfree() when they are no longer needed. Allocated + * name strings maby be "stolen" from the array but the pointer int the + * array should be nullified so that the string is not freed by + * ftpc_dirfree(). + */ + +struct ftpc_dirlist_s +{ + unsigned int nnames; /* Number of entries in name[] array */ + FAR char *name[1]; /* Filename with absolute path */ +}; + +#define SIZEOF_FTPC_DIRLIST(n) \ + (sizeof(struct ftpc_dirlist_s) + ((n)-1)*sizeof(FAR char *)) + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/* Connection management ****************************************************/ + +EXTERN SESSION ftpc_connect(FAR struct ftpc_connect_s *server); +EXTERN void ftpc_disconnect(SESSION handle); + +/* FTP commands *************************************************************/ + +EXTERN int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login); +EXTERN int ftpc_quit(SESSION handle); + +EXTERN int ftpc_chdir(SESSION handle, FAR const char *path); +EXTERN FAR char *ftpc_rpwd(SESSION handle); +EXTERN int ftpc_cdup(SESSION handle); +EXTERN int ftpc_mkdir(SESSION handle, FAR const char *path); +EXTERN int ftpc_rmdir(SESSION handle, FAR const char *path); + +EXTERN int ftpc_unlink(SESSION handle, FAR const char *path); +EXTERN int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode); +EXTERN int ftpc_rename(SESSION handle, FAR const char *oldname, FAR const char *newname); +EXTERN off_t ftpc_filesize(SESSION handle, FAR const char *path); +EXTERN time_t ftpc_filetime(SESSION handle, FAR const char *filename); + +EXTERN int ftpc_idle(SESSION handle, unsigned int idletime); +EXTERN int ftpc_noop(SESSION handle); +EXTERN int ftpc_help(SESSION handle, FAR const char *arg); + +/* Directory listings *******************************************************/ + +EXTERN FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle, + FAR const char *dirpath); +EXTERN void ftpc_dirfree(FAR struct ftpc_dirlist_s *dirlist); + +/* File transfers ***********************************************************/ + +EXTERN int ftpc_getfile(SESSION handle, FAR const char *rname, + FAR const char *lname, uint8_t how, uint8_t xfrmode); +EXTERN int ftp_putfile(SESSION handle, FAR const char *lname, + FAR const char *rname, uint8_t how, uint8_t xfrmode); + +/* FTP response *************************************************************/ + +EXTERN FAR char *ftpc_response(SESSION handle); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __APPS_INCLUDE_FTPC_H */ diff --git a/apps/include/netutils/dhcpc.h b/apps/include/netutils/dhcpc.h new file mode 100644 index 000000000..994a6713e --- /dev/null +++ b/apps/include/netutils/dhcpc.h @@ -0,0 +1,85 @@ +/**************************************************************************** + * apps/netutils/dhcpc.n + * + * Copyright (C) 2007, 2009-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * This logic was leveraged from uIP which also has a BSD-style license: + * + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __APPS_NETUTILS_DHCPC_H +#define __APPS_NETUTILS_DHCPC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct dhcpc_state +{ + struct in_addr serverid; + struct in_addr ipaddr; + struct in_addr netmask; + struct in_addr dnsaddr; + struct in_addr default_router; + uint32_t lease_time; /* Lease expires in this number of seconds */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +EXTERN void *dhcpc_open(const void *mac_addr, int mac_len); +EXTERN int dhcpc_request(void *handle, struct dhcpc_state *presult); +EXTERN void dhcpc_close(void *handle); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __APPS_NETUTILS_DHCPC_H */ diff --git a/apps/include/netutils/dhcpd.h b/apps/include/netutils/dhcpd.h new file mode 100644 index 000000000..b03415b20 --- /dev/null +++ b/apps/include/netutils/dhcpd.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * apps/netutils/dhcpd.h + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * This logic was leveraged from uIP which also has a BSD-style license: + * + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __APPS_NETUTILS_DHCPD_H +#define __APPS_NETUTILS_DHCPD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +EXTERN int dhcpd_run(void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __APPS_NETUTILS_DHCPD_H */ diff --git a/apps/include/netutils/httpd.h b/apps/include/netutils/httpd.h new file mode 100644 index 000000000..12f2a1511 --- /dev/null +++ b/apps/include/netutils/httpd.h @@ -0,0 +1,54 @@ +/**************************************************************************** + * apps/netutils/httpd.h + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based on uIP which also has a BSD style license: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2001-2005, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_HTTPD_H +#define __APPS_NETUTILS_HTTPD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +extern void httpd_init(void); +extern int httpd_listen(void); + +#endif /* __APPS_NETUTILS_HTTPD_H */ diff --git a/apps/include/netutils/ipmsfilter.h b/apps/include/netutils/ipmsfilter.h new file mode 100755 index 000000000..56088eca7 --- /dev/null +++ b/apps/include/netutils/ipmsfilter.h @@ -0,0 +1,101 @@ +/**************************************************************************** + * apps/netutils/ipmsfilter.h + * User interface to add/remove IP multicast address + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_IPMSFILTER_H +#define __APPS_NETUTILS_IPMSFILTER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <netinet/in.h> + +#ifdef CONFIG_NET_IGMP + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +# error "IGMP for IPv6 not supported" +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: ipmsfilter + * + * Description: + * Add or remove an IP address from a multicast filter set. + * (See netutils/uiplib/uip_ipmsfilter.c) + * + * Parameters: + * ifname The name of the interface to use, size must less than IMSFNAMSIZ + * multiaddr Multicast group address to add/remove + * fmode MCAST_INCLUDE: Add multicast address + * MCAST_EXCLUDE: Remove multicast address + * + * Return: + * 0 on sucess; Negated errno on failure + * + ****************************************************************************/ + +EXTERN int ipmsfilter(FAR const char *ifname, + FAR const struct in_addr *multiaddr, + uint32_t fmode); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* CONFIG_NET_IGMP */ +#endif /* __APPS_NETUTILS_IPMSFILTER_H */ diff --git a/apps/include/netutils/resolv.h b/apps/include/netutils/resolv.h new file mode 100644 index 000000000..a427c5394 --- /dev/null +++ b/apps/include/netutils/resolv.h @@ -0,0 +1,65 @@ +/* includes/apps/netutils/resolv.h + * DNS resolver code header file. + * Authtor Adam Dunkels <adam@dunkels.com> + * + * Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __APPS_NETUTILS_RESOLVE_H +#define __APPS_NETUTILS_RESOLVE_H + +#include <net/uip/uipopt.h> + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/* Functions. */ + +EXTERN int resolv_init(void); + +#ifdef CONFIG_NET_IPv6 +EXTERN void resolv_conf(const struct in6_addr *dnsserver); +EXTERN void resolv_getserver(const struct in_addr *dnsserver); +EXTERN int resolv_query(const char *name, struct sockaddr_in6 *addr); +#else +EXTERN void resolv_conf(const struct in_addr *dnsserver); +EXTERN void resolv_getserver(struct in_addr *dnsserver); +EXTERN int resolv_query(const char *name, struct sockaddr_in *addr); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __APPS_NETUTILS_RESOLVE_H */ diff --git a/apps/include/netutils/smtp.h b/apps/include/netutils/smtp.h new file mode 100644 index 000000000..d1ea0c5d9 --- /dev/null +++ b/apps/include/netutils/smtp.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * include/apps/netutils/smtp.h + * SMTP header file + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Heavily leveraged from uIP 1.0 which also has a BSD-like license: + * + * Author: Adam Dunkels <adam@dunkels.com> + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_SMTP_H +#define __APPS_NETUTILS_SMTP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <net/uip/uipopt.h> +#include <net/uip/uip.h> + +/**************************************************************************** + * Type Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +extern void *smtp_open(void); +extern void smtp_configure(void *handle, const char *localhostname, + const uip_ipaddr_t *paddr); +extern int smtp_send(void *handle, const char *to, const char *cc, + const char *from, const char *subject, + const char *msg, int msglen); +extern void smtp_close(void *handle); + +#endif /* __APPS_NETUTILS_SMTP_H */ diff --git a/apps/include/netutils/telnetd.h b/apps/include/netutils/telnetd.h new file mode 100644 index 000000000..9d3d6feaf --- /dev/null +++ b/apps/include/netutils/telnetd.h @@ -0,0 +1,70 @@ +/**************************************************************************** + * include/apps/netutils/telnetd.h + * + * Copyright (C) 2007, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * This is a leverage of similar logic from uIP: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_TELNETD_H +#define __APPS_NETUTILS_TELNETD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/* Start the telnet server -- does not return unless an error occurs */ + +EXTERN void telnetd_init(void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __APPS_NETUTILS_TELNETD_H */ diff --git a/apps/include/netutils/tftp.h b/apps/include/netutils/tftp.h new file mode 100644 index 000000000..c00e37c72 --- /dev/null +++ b/apps/include/netutils/tftp.h @@ -0,0 +1,73 @@ +/**************************************************************************** + * include/apps/netutils/tftp.h + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_TFTP_H +#define __APPS_NETUTILS_TFTP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdbool.h> +#include <arpa/inet.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +EXTERN int tftpget(const char *remote, const char *local, in_addr_t addr, bool binary); +EXTERN int tftpput(const char *local, const char *remote, in_addr_t addr, bool binary); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __APPS_NETUTILS_TFTP_H */
\ No newline at end of file diff --git a/apps/include/netutils/thttpd.h b/apps/include/netutils/thttpd.h new file mode 100644 index 000000000..959177219 --- /dev/null +++ b/apps/include/netutils/thttpd.h @@ -0,0 +1,101 @@ +/**************************************************************************** + * apps/netutils/thttpd.h + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_THTTPD_H +#define __APPS_NETUTILS_THTTPD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <nuttx/symtab.h> + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/* These values must be provided by the user before the THTTPD task daemon + * is started: + * + * g_thttpdsymtab: A symbol table describing all of the symbols exported + * from the base system. These symbols are used to bind address references + * in CGI programs to NuttX. + * g_nsymbols: The number of symbols in g_thttpdsymtab[]. + * + * (See examples/nxflat and examples/thttpd for examples of how such a symbol + * table may be created.) + */ + +EXTERN FAR const struct symtab_s *g_thttpdsymtab; +EXTERN int g_thttpdnsymbols; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Function: thttpd_main + * + * Description: + * This function is the entrypoint into the THTTPD server. It does not + * return. It may be called, the normal mechanism for starting the server + * is: + * + * 1) Set is g_thttpdsymtab and g_thttpdnsymbols. The user is required + * to provide a symbol table to use for binding CGI programs (if CGI + * is enabled. See examples/nxflat and examples/thttpd for examples of + * how such a symbol table may be created.) + * 2) Call task_create() to start thttpd_main() + * + ****************************************************************************/ + +EXTERN int thttpd_main(int argc, char **argv); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __APPS_NETUTILS_THTTPD_H */ diff --git a/apps/include/netutils/uiplib.h b/apps/include/netutils/uiplib.h new file mode 100644 index 000000000..a149de63b --- /dev/null +++ b/apps/include/netutils/uiplib.h @@ -0,0 +1,129 @@ +/**************************************************************************** + * apps/netutils/uiplib.h + * Various non-standard APIs to support netutils. All non-standard and + * intended only for internal use. + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Some of these APIs derive from uIP but all of them use the uip_ prefix + * to identify them as members of this library. uIP also has a BSD style + * license: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_UIPLIB_H +#define __APPS_NETUTILS_UIPLIB_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <pthread.h> + +#include <netinet/in.h> +#include <net/uip/uipopt.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* SOCK_DGRAM is the preferred socket type to use when we just want a + * socket for performing drive ioctls. However, we can't use SOCK_DRAM + * if UDP is disabled. + */ + +#ifdef CONFIG_NET_UDP +# define UIPLIB_SOCK_IOCTL SOCK_DGRAM +#else +# define UIPLIB_SOCK_IOCTL SOCK_STREAM +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Convert a textual representation of an IP address to a numerical representation. + * + * This function takes a textual representation of an IP address in + * the form a.b.c.d and converts it into a 4-byte array that can be + * used by other uIP functions. + * + * addrstr A pointer to a string containing the IP address in + * textual form. + * + * addr A pointer to a 4-byte array that will be filled in with + * the numerical representation of the address. + * + * Return: 0 If the IP address could not be parsed. + * Return: Non-zero If the IP address was parsed. + */ + +extern bool uiplib_ipaddrconv(const char *addrstr, uint8_t *addr); + +/* Get and set IP/MAC addresses (Ethernet L2 only) */ + +#ifdef CONFIG_NET_ETHERNET +extern int uip_setmacaddr(const char *ifname, const uint8_t *macaddr); +extern int uip_getmacaddr(const char *ifname, uint8_t *macaddr); +#endif + +/* IP address support */ + +#ifdef CONFIG_NET_IPv6 +extern int uip_gethostaddr(const char *ifname, struct in6_addr *addr); +extern int uip_sethostaddr(const char *ifname, const struct in6_addr *addr); +extern int uip_setdraddr(const char *ifname, const struct in6_addr *addr); +extern int uip_setnetmask(const char *ifname, const struct in6_addr *addr); +#else +extern int uip_gethostaddr(const char *ifname, struct in_addr *addr); +extern int uip_sethostaddr(const char *ifname, const struct in_addr *addr); +extern int uip_setdraddr(const char *ifname, const struct in_addr *addr); +extern int uip_setnetmask(const char *ifname, const struct in_addr *addr); +#endif + +/* HTTP support */ + +extern int uip_parsehttpurl(const char *url, uint16_t *port, + char *hostname, int hostlen, + char *filename, int namelen); + +/* Generic server logic */ + +extern void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize); + +#endif /* __APPS_NETUTILS_UIPLIB_H */ diff --git a/apps/include/netutils/webclient.h b/apps/include/netutils/webclient.h new file mode 100644 index 000000000..c80626e3b --- /dev/null +++ b/apps/include/netutils/webclient.h @@ -0,0 +1,149 @@ +/**************************************************************************** + * include/apps/netutils/webclient.h + * Header file for the HTTP client + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based remotely on the uIP webclient which also has a BSD style license: + * + * Author: Adam Dunkels <adam@dunkels.com> + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_WEBCLIENT_H +#define __APPS_NETUTILS_WEBCLIENT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifndef CONFIG_WEBCLIENT_HOST +# include <nuttx/config.h> +#endif +#include <sys/types.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_WEBCLIENT_MAXHTTPLINE +# define CONFIG_WEBCLIENT_MAXHTTPLINE 200 +#endif + +#ifndef CONFIG_WEBCLIENT_MAXMIMESIZE +# define CONFIG_WEBCLIENT_MAXMIMESIZE 32 +#endif + +#ifndef CONFIG_WEBCLIENT_MAXHOSTNAME +# define CONFIG_WEBCLIENT_MAXHOSTNAME 40 +#endif + +#ifndef CONFIG_WEBCLIENT_MAXFILENAME +# define CONFIG_WEBCLIENT_MAXFILENAME 100 +#endif + +/**************************************************************************** + * Public types + ****************************************************************************/ + +/* wget calls a user provided function of the follwoing type to process + * each received chuck of the incoming file data. If the system has a file + * system, then it may just write the data to a file. Or it may buffer the + * file in memory. To facilitate this latter case, the caller may modify + * the buffer address in this callback by writing to buffer and buflen. This + * may be used, for example, to implement double buffering. + * + * Input Parameters: + * buffer - A pointer to a pointer to a buffer. If the callee wishes to + * change the buffer address, it may do so in the callback by writing + * to buffer. + * offset - Offset to the beginning of valid data in the buffer. Offset + * is used to skip over any HTTP header info that may be at the + * beginning of the buffer. + * datend - The end+1 offset of valid data in the buffer. The total number + * of valid bytes is datend - offset. + * buflen - A pointer to the length of the buffer. If the callee wishes + * to change the size of the buffer, it may write to buflen. + */ + +typedef void (*wget_callback_t)(FAR char **buffer, int offset, + int datend, FAR int *buflen, FAR void *arg); + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: wget + * + * Description: + * Obtain the requested file from an HTTP server using the GET method. + * + * Note: If the function is passed a host name, it must already be in + * the resolver cache in order for the function to connect to the web + * server. It is therefore up to the calling module to implement the + * resolver calls and the signal handler used for reporting a resolv + * query answer. + * + * Input Parameters + * url - A pointer to a string containing either the full URL to + * the file to get (e.g., http://www.nutt.org/index.html, or + * http://192.168.23.1:80/index.html). + * buffer - A user provided buffer to receive the file data (also + * used for the outgoing GET request + * buflen - The size of the user provided buffer + * callback - As data is obtained from the host, this function is + * to dispose of each block of file data as it is received. + * arg - User argument passed to callback. + * + * Returned Value: + * 0: if the GET operation completed successfully; + * -1: On a failure with errno set appropriately + * + ****************************************************************************/ + +EXTERN int wget(FAR const char *url, FAR char *buffer, int buflen, + wget_callback_t callback, FAR void *arg); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __APPS_NETUTILS_WEBCLIENT_H */ diff --git a/apps/include/nsh.h b/apps/include/nsh.h new file mode 100644 index 000000000..6977e44bd --- /dev/null +++ b/apps/include/nsh.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * include/apps/nsh.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_APPS_NSHLIB_H +#define __INCLUDE_APPS_NSHLIB_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +#if CONFIG_RR_INTERVAL > 0 +# define SCHED_NSH SCHED_RR +#else +# define SCHED_NSH SCHED_FIFO +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Interfaces needed to initialize and execute the NuttShell (NSH). + * + * nsh_initialize() - This function function should be called one during + * application start-up prior to executing nsh_consolemain() or + * nsh_telnetmain(). + */ + +EXTERN void nsh_initialize(void); + +/* The following interfaces maybe to called or started with task_start to + * start an NSH instance. + * + * nsh_consolemain() starts NSH on the console (/dev/console). + * nsh_telnetmain() starts a telnet daemon that will allow multiple + * connections via telnet. + * + * These functions do not return. + */ + +EXTERN int nsh_consolemain(int argc, char *argv[]); +EXTERN int nsh_telnetmain(int argc, char *argv[]); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_APPS_NSHLIB_H */ diff --git a/apps/include/tiff.h b/apps/include/tiff.h new file mode 100644 index 000000000..353005599 --- /dev/null +++ b/apps/include/tiff.h @@ -0,0 +1,465 @@ +/************************************************************************************ + * apps/include/tiff.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Reference: + * "TIFF, Revision 6.0, Final," June 3, 1992, Adobe Developers Association. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __APPS_INCLUDE_TIFF_H +#define __APPS_INCLUDE_TIFF_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include <nuttx/config.h> +#include <sys/types.h> +#include <nuttx/nx/nxglib.h> + +/************************************************************************************ + * Pre-Processor Definitions + ************************************************************************************/ +/* Configuration ********************************************************************/ + +/* TIFF File Format Definitions *****************************************************/ +/* Values for the IFD field type */ + +#define IFD_FIELD_BYTE 1 /* 8-bit unsigned integer */ +#define IFD_FIELD_ASCII 2 /* 8-bit byte that contains a 7-bit ASCII code. + * The last byte must be NUL */ +#define IFD_FIELD_SHORT 3 /* 16-bit (2-byte) unsigned integer */ +#define IFD_FIELD_LONG 4 /* 32-bit (4-byte) unsigned integer */ +#define IFD_FIELD_RATIONAL 5 /* Two LONGs: the first represents the + * numerator of a fraction, the second the + * denominator */ +#define IFD_FIELD_SBYTE 6 /* An 8-bit signed (twos-complement) integer */ +#define IFD_FIELD_UNDEFINED 7 /* An 8-bit byte that may contain anything, + * depending on the definition of the field */ +#define IFD_FIELD_SSHORT 8 /* A 16-bit (2-byte) signed (twos-complement) + * integer */ +#define IFD_FIELD_SLONG 9 /* A 32-bit (4-byte) signed (twos-complement) + * integer */ +#define IFD_FIELD_SRATIONAL 10 /* Two SLONG’s: the first represents the + * numerator of a fraction, the second the + * denominator */ +#define IFD_FIELD_FLOAT 11 /* Single precision (4-byte) IEEE format */ +#define IFD_FIELD_DOUBLE 12 /* Double precision (8-byte) IEEE format */ + +/* Values for the IFD tag type */ + +#define IFD_TAG_NEWSUBFILETYPE 254 /* NewSubfileType, LONG */ +# define TAG_NEWSUBFILETYPE_REDUCED (1 << 0) /* Bit 0: Reduced resolution verson of image */ +# define TAG_NEWSUBFILETYPE_SINGLE (1 << 1) /* Bit 1: Single page of a multi-page image */ +# define TAG_NEWSUBFILETYPE_TRANSP (1 << 2) /* Bit 2: Defines a transparency mask for image */ +#define IFD_TAG_SUBFILETYPE 255 /* SubfileType, SHORT */ +# define TAG_SUBFILETYPE_FULL 1 /* Full-resolution image data */ +# define TAG_SUBFILETYPE_REDUCED 2 /* Reduced-resolution image data */ +# define TAG_SUBFILETYPE_SINGLE 3 /* Single page of a multi-page image */ +#define IFD_TAG_IMAGEWIDTH 256 /* ImageLength, SHORT or LONG (Required) */ +#define IFD_TAG_IMAGELENGTH 257 /* ImageWidth, SHORT or LONG (Required) */ +#define IFD_TAG_BITSPERSAMPLE 258 /* BitsPerSample, SHORT (Required + * in greyscale and pallette-color image files) */ +#define IFD_TAG_COMPRESSION 259 /* Compression, SHORT (Required) */ +# define TAG_COMP_NONE 1 /* No compression */ +# define TAG_COMP_CCITT 2 /* CCITT Group 3 1-Dimensional Modified Huffman + * run length encoding */ +# define TAG_COMP_T4 3 /* CCITT T.4 bi-level encoding */ +# define TAG_COMP_T6 4 /* CCITT T.6 bi-level encoding */ +# define TAG_COMP_LZW 5 /* LZW */ +# define TAG_COMP_JPEG 6 /* LZW */ +# define TAG_COMP_PACKBITS 32773 /* PackBits compression */ +#define IFD_TAG_PMI 262 /* PhotometricInterpretation, SHORT (Required) */ +# define TAG_PMI_WHITE 0 /* WhiteIsZero */ +# define TAG_PMI_BLACK 1 /* BlackIsZero */ +# define TAG_PMI_RGB 2 /* RGB */ +# define TAG_PMI_PALETTE 3 /* Palette color */ +# define TAG_PMI_TRANSP 4 /* Transparency mask */ +# define TAG_PMI_CMYK 5 /* CMYK */ +# define TAG_PMI_YCbCr 6 /* YCbCr */ +# define TAG_PMI_CIELAB 8 /* 1976 CIE L*a*b* */ +#define IFD_TAG_THRESHHOLDING 263 /* Threshholding, SHORT */ +# define TAG_THRESHHOLD_NONE 1 /* No dithering or halftoning has been applied */ +# define TAG_THRESHHOLD_ORDERED 2 /* Ordered dither or halftone technique has been applied */ +# define TAG_THRESHHOLD_RANDOM 3 /* Randomized process has been applied */ +#define IFD_TAG_CELLWIDTH 264 /* CellWidth, SHORT */ +#define IFD_TAG_CELLLENGTH 265 /* CellLength, SHORT */ +#define IFD_TAG_FILLORDER 266 /* FillOrder, SHORT */ +# define TAG_FILLORDER_HIGH 1 /* Lower column values are stored in the + * higher-order bits */ +# define TAG_FILLORDER_LOW 2 /* Lower column values are stored in the + * lower-order bits */ +#define IFD_TAG_DOCUMENTNAME 269 /* DocumentName, ASCII */ +#define IFD_TAG_IMAGEDESCRIPTION 270 /* ImageDescription, ASCII */ +#define IFD_TAG_MAKE 271 /* Make, ASCII */ +#define IFD_TAG_MODEL 272 /* Model, ASCII */ +#define IFD_TAG_STRIPOFFSETS 273 /* StripOffsets, SHORT or LONG (Required) */ +#define IFD_TAG_ORIENTATION 274 /* Orientation, SHORT */ +# define TAG_ORIENTATION_TL 1 /* (0,0)=top left */ +# define TAG_ORIENTATION_TR 2 /* (0,0)=top right */ +# define TAG_ORIENTATION_BR 3 /* (0,0)=bottom right */ +# define TAG_ORIENTATION_BL 4 /* (0,0)=bottom left */ +# define TAG_ORIENTATION_LT 5 /* (0,0)=left top */ +# define TAG_ORIENTATION_RT 6 /* (0,0)=right top */ +# define TAG_ORIENTATION_RB 7 /* (0,0)=right bottom */ +# define TAG_ORIENTATION_LB 8 /* (0,0)=left bottom */ +#define IFD_TAG_SAMPLESPERPIXEL 277 /* SamplesPerPixel, SHORT (Required in + * RGB full color files) */ +#define IFD_TAG_ROWSPERSTRIP 278 /* RowsPerStrip, SHORT or LONG (Required) */ +#define IFD_TAG_STRIPCOUNTS 279 /* StripByteCounts, SHORT or LONG (Required) */ +#define IFD_TAG_MINSAMPLEVALUE 280 /* MinSampleValue, SHORT */ +#define IFD_TAG_MAXSAMPLEVALUE 281 /* MaxSampleValue, SHORT */ +#define IFD_TAG_XRESOLUTION 282 /* XResolution, RATIONAL (Required) */ +#define IFD_TAG_YRESOLUTION 283 /* YResolution, RATIONAL (Required) */ +#define IFD_TAG_PLANARCONFIG 284 /* PlanarConfiguration, SHORT */ +# define TAG_PLCONFIG_CHUNKY 1 /* Chunky format */ +# define TAG_PLCONFIG_PLANAR 2 /* Planar format */ +#define IFD_TAG_PAGENAME 285 /* PageName, ASCII */ +#define IFD_TAG_XPOSITION 286 /* XPosition, RATIONAL */ +#define IFD_TAG_YPOSITION 287 /* YPosition, RATIONAL */ +#define IFD_TAG_FREEOFFSETS 288 /* FreeOffsets, LONG */ +#define IFD_TAG_FREEBYTECOUNTS 289 /* FreeByteCounts, LONG */ +#define IFD_TAG_GRAYRESPONSEUNIT 290 /* GrayResponseUnit, SHORT */ +# define TAG_GRAYRESPUNIT_10THS 1 /* Number represents tenths of a unit */ +# define TAG_GRAYRESPUNIT_100THS 2 /* Number represents hundredths of a unit */ +# define TAG_GRAYRESPUNIT_1KTHS 3 /* Number represents thousandths of a unit */ +# define TAG_GRAYRESPUNIT_10KTHS 4 /* Number represents ten-thousandths of a unit */ +# define TAG_GRAYRESPUNIT_100KTHS 5 /* Number represents hundred-thousandths of a unit */ +#define IFD_TAG_GRAYRESPONSECURVE 291 /* GrayResponseCurve, SHORT */ +#define IFD_TAG_T4OPTIONS 292 /* T4Options, LONG */ +# define TAG_T4OPTIONS_2D (1 << 0) /* 2-dimensional coding */ +# define TAG_T4OPTIONS_NONE (1 << 1) /* Uncompressed mode */ +# define TAG_T4OPTIONS_FILL (1 << 2) /* Fill bits have been added */ +#define IFD_TAG_T6OPTIONS 293 /* T6Options, LONG */ +# define TAG_T6OPTIONS_NONE (1 << 1) /* Uncompressed mode allowed */ +#define IFD_TAG_RESUNIT 296 /* ResolutionUnit, SHORT (Required) */ +# define TAG_RESUNIT_NONE 1 /* No absolute unit of measurement */ +# define TAG_RESUNIT_INCH 2 /* Inch (default) */ +# define TAG_RESUNIT_CENTIMETER 3 /* Centimeter */ +#define IFD_TAG_PAGENUMBER 297 /* PageNumber, SHORT */ +#define IFD_TAG_TRANSFERFUNCTION 301 /* TransferFunction, SHORT */ +#define IFD_TAG_SOFTWARE 305 /* Software, ASCII */ +#define IFD_TAG_DATETIME 306 /* DateTime, ASCII */ +#define IFD_TAG_ARTIST 315 /* Artist, ASCII */ +#define IFD_TAG_HOSTCOMPUTER 316 /* HostComputer, ASCII */ +#define IFD_TAG_PREDICTOR 317 /* Predictor SHORT */ +# define TAG_PREDICTOR_NONE 1 /* No prediction scheme used before coding */ +# define TAG_PREDICTOR_HORIZ 2 /* Horizontal differencing */ +#define IFD_TAG_WHITEPOINT 318 /* WhitePoint, RATIONAL */ +#define IFD_TAG_PRIMARYCHROMA 319 /* PrimaryChromaticities, RATIONAL */ +#define IFD_TAG_COLORMAP 320 /* ColorMap, SHORT (Required in palette + * color image files) */ +#define IFD_TAG_HALFTONEHINTS 321 /* HalftoneHints, SHORT */ +#define IFD_TAG_TILEWIDTH 322 /* TileWidth, SHORT or LONG */ +#define IFD_TAG_TILELENGTH 323 /* TileLength, SHORT or LONG */ +#define IFD_TAG_TILEOFFSETS 324 /* TileOffsets, LONG */ +#define IFD_TAG_TILEBYTECOUNTS 325 /* TileByteCounts, SHORT or LONG */ +#define IFD_TAG_INKSET 332 /* InkSet, SHORT */ +# define TAG_INKSET_CMYK 1 /* CMYK */ +# define TAG_INKSET_OTHER 2 /* Not CMYK */ +#define IFD_TAG_INKNAMES 333 /* InkNames, ASCII */ +#define IFD_TAG_NUMBEROFINKS 334 /* NumberOfInks, SHORT */ +#define IFD_TAG_DOTRANGE 336 /* DotRange, BYTE or SHORT */ +#define IFD_TAG_TARGETPRINTER 337 /* TargetPrinter, ASCII */ +#define IFD_TAG_EXTRASAMPLES 338 /* ExtraSamples, SHORT */ +# define TAG_EXTSAMP_UNSPEC 0 /* Unspecified */ +# define TAG_EXTSAMP_ASSOCALPHA 1 /* Associated alpha data */ +# define TAG_EXTSAMP_UNASSALPHA 2 /* Unassociated alpha data */ +#define IFD_TAG_SAMPLEFORMAT 339 /* SampleFormat, SHORT */ +# define TAG_SAMPLEFMT_UNSIGED 1 /* Unsigned integer data */ +# define TAG_SAMPLEFMT_SIGNED 2 /* Two’s complement signed integer data */ +# define TAG_SAMPLEFMT_FLOAT 3 /* IEEE floating point data */ +# define TAG_SAMPLEFMT_UNDEFINED 4 /* Undefined data format */ +#define IFD_TAG_SMINSAMPLEVALUE 340 /* SMinSampleValue, type matches sample data */ +#define IFD_TAG_SMAXSAMPLEVALUE 341 /* SMaxSampleValue, type matches sample data */ +#define IFD_TAG_TRANSFERRANGE 342 /* TransferRange, SHORT */ +#define IFD_TAG_JPEGPROC 512 /* JPEGProc, SHORT */ +#define IFD_TAG_JPEGFMT 513 /* JPEGInterchangeFormat, LONG */ +#define IFD_TAG_JPEGLENGTH 514 /* JPEGInterchangeFormatLength, LONG */ +#define IFD_TAG_JPEGRESTART 515 /* JPEGRestartInterval, SHORT */ +#define IFD_TAG_JPEGLLPREDICTORS 517 /* JPEGLosslessPredictors, SHORT */ +#define IFD_TAG_JPEGPOINTXFORMS 518 /* JPEGPointTransforms, SHORT */ +#define IFD_TAG_JPEGQTABLES 519 /* JPEGQTables, LONG */ +#define IFD_TAG_JPEGDCTABLES 520 /* JPEGDCTables, LONG */ +#define IFD_TAG_JPEGACTABLES 521 /* JPEGACTables, LONG */ +#define IFD_TAG_YCbCrCOEFFS 529 /* YCbCrCoefficients, RATIONAL */ +#define IFD_TAG_YCbCrSUBSAMPLING 530 /* YCbCrSubSampling, SHORT */ +#define IFD_TAG_YCbCrPOSITIONING 531 /* YCbCrPositioning, SHORT */ +#define IFD_TAG_REFERENCEBW 532 /* ReferenceBlackWhite, RATIONAL */ +#define IFD_TAG_COPYRIGHT 33432 /* Copyright, ASCII */ + +/************************************************************************************ + * Public Types + ************************************************************************************/ +/* TIFF File Format Structure *******************************************************/ +/* "A TIFF file begins with an 8-byte image file header that points to an + * image file directory (IFD). An image file directory contains information + * about the image, as well as pointers to the actual image data." + */ + +struct tiff_header_s +{ + uint8_t order[2]; /* 0-1: Byte order: "II"=little endian, "MM"=big endian */ + uint8_t magic[2]; /* 2-3: 42 in appropriate byte order */ + uint8_t offset[4]; /* 4-7: Offset to the first IFD */ +}; +#define SIZEOF_TIFF_HEADER 8 + +/* "An Image File Directory (IFD) consists of a 2-byte count of the number + * of directory entries (i.e., the number of fields), followed by a sequence + * of 12-byte field entries, followed by a 4-byte offset of the next IFD (or + * 0 if none). + * + * Each 12-byte IFD entry has the following format: + */ + +struct tiff_ifdentry_s +{ + uint8_t tag[2]; /* 0-1: The Tag that identifies the field */ + uint8_t type[2]; /* 2-3 The field Type */ + uint8_t count[4]; /* 4-7: The number of values of the indicated type */ + uint8_t offset[4]; /* 8-11: The Value Offset (or the value itself) */ +}; +#define SIZEOF_IFD_ENTRY 12 + +/************************************************************************************/ +/* Structures needed to interface with the TIFF file creation library )and also + * structures used only internally by the TIFF file creation library). + */ + +/* This structure describes on strip in tmpfile2 */ + +struct tiff_strip_s +{ + uint32_t offset; /* Offset to the strip data in tmpfile1 */ + uint32_t count; /* Count of pixels in the strip */ +}; + +/* This structure is used only internally by the TIFF file creation library to + * manage file offsets. + */ + +struct tiff_filefmt_s +{ + uint16_t nifdentries; /* Number of IFD entries */ + uint16_t soifdoffset; /* Offset to StripOffset IFD entry */ + uint16_t sbcifdoffset; /* Offset to StripByteCount IFD entry */ + uint16_t valoffset; /* Offset to first values */ + uint16_t xresoffset; /* Offset to XResolution values */ + uint16_t yresoffset; /* Offset to yResolution values */ + uint16_t swoffset; /* Offset to Software string */ + uint16_t dateoffset; /* Offset to DateTime string */ + uint16_t sbcoffset; /* Offset to StripByteCount values */ +}; + +/* These type is used to hold information about the TIFF file under + * construction + */ + +struct tiff_info_s +{ + /* The first fields are used to pass information to the TIFF file creation + * logic via tiff_initialize(). + * + * Filenames. Three file names are required. (1) path to the final + * output file and (2) two paths to temporary files. One temporary file + * (tmpfile1) will be used to hold the strip image data and the other + * (tmpfile2) will be used to hold strip offset and count information. + * + * colorfmt - Specifies the form of the color data that will be provided + * in the strip data. These are the FB_FMT_* definitions + * provided in include/nuttx/fb.h. Only the following values + * are supported: + * + * FB_FMT_Y1 BPP=1, monochrome, 0=black + * FB_FMT_Y4 BPP=4, 4-bit greyscale, 0=black + * FB_FMT_Y8 BPP=8, 8-bit greyscale, 0=black + * FB_FMT_RGB16_565 BPP=16 R=6, G=6, B=5 + * FB_FMT_RGB24 BPP=24 R=8, G=8, B=8 + * + * rps - TIFF RowsPerStrip + * imgwidth - TIFF ImageWidth, Number of columns in the image + * imgheight - TIFF ImageLength, Number of rows in the image + */ + + FAR const char *outfile; /* Full path to the final output file name */ + FAR const char *tmpfile1; /* Full path to first temporary file */ + FAR const char *tmpfile2; /* Full path to second temporary file */ + + uint8_t colorfmt; /* See FB_FMT_* definitions in include/nuttx/fb.h */ + nxgl_coord_t rps; /* TIFF RowsPerStrip */ + nxgl_coord_t imgwidth; /* TIFF ImageWidth, Number of columns in the image */ + nxgl_coord_t imgheight; /* TIFF ImageLength, Number of rows in the image */ + + /* The caller must provide an I/O buffer as well. This I/O buffer will + * used for color conversions and as the intermediate buffer for copying + * files. The larger the buffer, the better the performance. + */ + + FAR uint8_t *iobuffer; /* IO buffer allocated by the caller */ + unsigned int iosize; /* The size of the I/O buffer in bytes */ + + /* The second set of fields are used only internally by the TIFF file + * creation logic. These fields must be set to zero initially by the + * caller of tiff_initialize(). User logic should not depend upon any + * definitions in the following -- they are subject to change without + * notice. They are only exposed here so that the caller can allocate + * memory for their storage. + */ + + uint8_t imgflags; /* Bit-encoded image flags */ + nxgl_coord_t nstrips; /* Number of strips in tmpfile3 */ + size_t pps; /* Pixels per strip */ + size_t bps; /* Bytes per strip */ + int outfd; /* outfile file descriptor */ + int tmp1fd; /* tmpfile1 file descriptor */ + int tmp2fd; /* tmpfile2 file descriptor */ + off_t outsize; /* Current size of outfile */ + off_t tmp1size; /* Current size of tmpfile1 */ + off_t tmp2size; /* Current size of tmpfile2 */ + + /* Points to an internal constant structure of file offsets */ + + FAR const struct tiff_filefmt_s *filefmt; +}; + +/************************************************************************************ + * Public Function Prototypes + ************************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/************************************************************************************ + * Name: tiff_initialize + * + * Description: + * Setup to create a new TIFF file. The overall steps to creating a TIFF file are + * as follows: + * + * 1) Create an initialize a struct tiff_info_s instance + * 2) Call tiff_initialize() to setup the file creation + * 3) Call tiff_addstrip() repeatedly to add strips to the graphic image + * 4) Call tiff_finalize() to complete the file creation. + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state instance. + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ************************************************************************************/ + +EXTERN int tiff_initialize(FAR struct tiff_info_s *info); + +/************************************************************************************ + * Name: tiff_addstrip + * + * Description: + * Add an image data strip. The size of the strip in pixels must be equal to + * the RowsPerStrip x ImageWidth values that were provided to tiff_initialize(). + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state instance. + * buffer - A buffer containing a single row of data. + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ************************************************************************************/ + +EXTERN int tiff_addstrip(FAR struct tiff_info_s *info, FAR const uint8_t *strip); + +/************************************************************************************ + * Name: tiff_finalize + * + * Description: + * Finalize the TIFF output file, completing the TIFF file creation steps. + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state instance. + * + * Returned Value: + * Zero (OK) on success. A negated errno value on failure. + * + ************************************************************************************/ + +EXTERN int tiff_finalize(FAR struct tiff_info_s *info); + +/************************************************************************************ + * Name: tiff_abort + * + * Description: + * Abort the TIFF file creation and create-up resources. + * + * Input Parameters: + * info - A pointer to the caller allocated parameter passing/TIFF state instance. + * + * Returned Value: + * None + * + ************************************************************************************/ + +EXTERN void tiff_abort(FAR struct tiff_info_s *info); + +/************************************************************************************ + * Name: tiff_put/get16/32 + * + * Description: + * Put and get 16 and 32 values in the correct byte order at the specified position. + * + * Input Parameters: + * dest - The location to store the multi-byte data (put only) + * src - The location to get the multi-byte data (get only) + * + * Returned Value: + * None (put) + * The extracted value (get) + * + ************************************************************************************/ + +EXTERN void tiff_put16(FAR uint8_t *dest, uint16_t value); +EXTERN void tiff_put32(FAR uint8_t *dest, uint32_t value); +EXTERN uint16_t tiff_get16(FAR uint8_t *dest); +EXTERN uint32_t tiff_get32(FAR uint8_t *dest); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __APPS_INCLUDE_TIFF_H */ diff --git a/apps/interpreters/Makefile b/apps/interpreters/Makefile new file mode 100644 index 000000000..1ef9c7439 --- /dev/null +++ b/apps/interpreters/Makefile @@ -0,0 +1,70 @@ +############################################################################ +# apps/interpreters/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration + +# Sub-directories containing interpreter runtime + +SUBDIRS = pcode ficl + +# Create the list of installed runtime modules (INSTALLED_DIRS) + +define ADD_DIRECTORY +INSTALLED_DIRS += ${shell if [ -r $1/Makefile ]; then echo "$1"; fi} +endef + +$(foreach DIR, $(SUBDIRS), $(eval $(call ADD_DIRECTORY,$(DIR)))) + +all: nothing +.PHONY: nothing context depend clean distclean + +nothing: + +context: + +depend: + @for dir in $(INSTALLED_DIRS) ; do \ + $(MAKE) -C $$dir depend TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +clean: + @for dir in $(INSTALLED_DIRS) ; do \ + $(MAKE) -C $$dir clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +distclean: clean + @for dir in $(INSTALLED_DIRS) ; do \ + $(MAKE) -C $$dir distclean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done diff --git a/apps/interpreters/README.txt b/apps/interpreters/README.txt new file mode 100644 index 000000000..8cf7ce321 --- /dev/null +++ b/apps/interpreters/README.txt @@ -0,0 +1,67 @@ +apps/interpreters README file +============================= + +This apps/ directory is set aside to hold interpreters that may be +incorporated into NuttX. + +ficl +---- + + This is DIY port of Ficl (the "Forth Inspired Command Language"). See + http://ficl.sourceforge.net/. It is a "DIY" port because the Ficl source + is not in that directory, only an environment and instructions that will + let you build Ficl under NuttX. The rest is up to you. + +pcode +----- + + At present, only the NuttX Pascal add-on is supported. This NuttX add-on + must be downloaded separately (or is available in an SVN snapshot in the + misc/pascal directory). + + This Pascal add-on must be installed into the NuttX apps/ directory. After + unpacking the Pascal add-on package, an installation script and README.txt + instructions can be found at pascal/nuttx. + + INSTALL.sh -- The script that performs the operation. Usage: + + ./INSTALL.sh [-16|-32] <install-dir> + + If you are using this standard NuttX apps/ package, the correct + location for the <install-dir> is apps/interpreters. That is + where the examples and build logic will expect to find the pcode + sub-directory. + + Example: + + ./INSTALL.sh -16 $PWD/../../../apps/interpreters + + After installation, the NuttX apps/interpresters directory will contain + the following files + + pcode + |-- Makefile + |-- include + | `-- Common header files + |-- libboff + | `-- Pascal object format (POFF) library + `--insn + |-- include + | `-- model-specific header files + `-- prun + `-- model-specific source files + + pashello + + There is a simple Pascal example at apps/examples/pashello. This is the + standard "Hello, World!" example written in Pascal and interpreted from + Pascal P-Code at runtime. To use this example, place the following in + your appconfig file" + + # Path to example in apps/examples containing the user_start entry point + + CONFIGURED_APPS += examples/pashello + + # Path to the Pascal p-code runtime interpreter module + + CONFIGURED_APPS += interpreters/pcode diff --git a/apps/interpreters/ficl/Makefile b/apps/interpreters/ficl/Makefile new file mode 100644 index 000000000..183246b67 --- /dev/null +++ b/apps/interpreters/ficl/Makefile @@ -0,0 +1,118 @@ +############################################################################ +# apps/interpreters/ficl/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +BUILDDIR := ${shell pwd | sed -e 's/ /\\ /g'} + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Tools + +INCDIR = $(TOPDIR)/tools/incdir.sh + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +# Include paths + +CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(BUILDDIR)/$(FICL_SUBDIR) $(BUILDDIR)/src} + +# Source Files + +ASRCS = +CXXSRCS = +CSRCS = nuttx.c + +-include Make.srcs + +ASRCS += $(FICL_ASRCS) +CXXSRCS += $(FICL_CXXSRCS) +CSRCS += $(FICL_CSRCS) + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOT_DEPPATH = --dep-path . +SRC_DEPPATH = --dep-path src + +VPATH = src:$(FICL_SUBDIR) + +all: .built +.PHONY: debug context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +debug: + @#echo "FICL: $(FICL_SUBDIR)" + @#echo "VPATH: $(VPATH)" + @#echo "CFLAGS: $(CFLAGS)" + +.built: debug $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: debug Makefile $(SRCS) + @$(MKDEP) $(ROOT_DEPPATH) $(SRC_DEPPATH) $(FICL_DEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/interpreters/ficl/README.txt b/apps/interpreters/ficl/README.txt new file mode 100755 index 000000000..d775db1e8 --- /dev/null +++ b/apps/interpreters/ficl/README.txt @@ -0,0 +1,42 @@ +apps/interpreter/README.txt
+===========================
+
+Ficl is a programming language interpreter designed to be embedded into
+other systems as a command, macro, and development prototyping language.
+Ficl is an acronym for "Forth Inspired Command Language". See
+http://ficl.sourceforge.net/
+
+Build Instructions
+------------------
+
+Disclaimer: This installation steps have only been exercised using Ficl
+4.1.0. With new versions you will likely have to make some adjustments
+to this instructtions or to the files within this directory. This of this
+information as "recommendations" -- not necessarily proven instructions.
+
+1. CD to apps/interpreters/ficl
+
+2. Download Ficl: http://sourceforge.net/projects/ficl/files/
+
+3. Uznip the Ficl compressed file.
+
+ For example, 'unzip ficl-4.1.0.zip' will leave the file
+ apps/interpreters/ficl/ficl-4.1.0
+
+4. Configure to build Ficl in the apps/interpreters/ficl directory using
+ the configure.sh script.
+
+ For example, './configure.sh ficl-4.1.0' will leave the Makefile
+ fragment 'Make.srcs' in the ficl build directory.
+
+5. Create your NuttX configuration. The appconfig file should include
+ (1) the path to your application code, and (2) the path to the Ficl
+ build directory. That latter would appear as the following line in
+ your appconfig file:
+
+ CONFIGURED_APPS += interpreters/ficl
+
+ 6. Configure and build NuttX. On successful completion, the Ficl objects
+ will be available in apps/libapps.a and that NuttX binary will be
+ linked against that file. Of course, Ficl will do nothing unless
+ you have written some application code that uses it!
diff --git a/apps/interpreters/ficl/configure.sh b/apps/interpreters/ficl/configure.sh new file mode 100755 index 000000000..cadc1d48a --- /dev/null +++ b/apps/interpreters/ficl/configure.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +USAGE="$0 <Ficl-dir>" + +FICLDIR=$1 +if [ -z "${FICLDIR}" ]; then + echo "Missing command line argument" + echo $USAGE + exit 1 +fi + +if [ ! -d "${FICLDIR}" ]; then + echo "Sub-directory ${FICLDIR} does not exist" + echo $USAGE + exit 1 +fi + +if [ ! -r "${FICLDIR}/Makefile" ]; then + echo "Readable ${FICLDIR}/Makefile does not exist" + echo $USAGE + exit 1 +fi + +OBJECTS=`grep "^OBJECTS" ${FICLDIR}/Makefile` +if [ -z "${OBJECTS}" ]; then + echo "No OBJECTS found in ${FICLDIR}/Makefile" + echo $USAGE + exit 1 +fi + +OBJLIST=`echo ${OBJECTS} | cut -d'=' -f2 | sed -e "s/unix\.o//g"` + +rm -f Make.srcs +echo "# apps/interpreters/ficl/Make.obs" >> Make.srcs +echo "# Auto-generated file.. Do not edit" >> Make.srcs +echo "" >> Make.srcs +echo "FICL_SUBDIR = ${1}" >> Make.srcs +echo "FICL_DEPPATH = --dep-path ${1}" >> Make.srcs + +unset CSRCS +for OBJ in ${OBJLIST}; do + SRC=`echo ${OBJ} | sed -e "s/\.o/\.c/g"` + CSRCS=${CSRCS}" ${SRC}" +done +echo "FICL_ASRCS = " >> Make.srcs +echo "FICL_CXXSRCS = " >> Make.srcs +echo "FICL_CSRCS = ${CSRCS}" >> Make.srcs diff --git a/apps/interpreters/ficl/src/nuttx.c b/apps/interpreters/ficl/src/nuttx.c new file mode 100644 index 000000000..16b3fa1db --- /dev/null +++ b/apps/interpreters/ficl/src/nuttx.c @@ -0,0 +1,65 @@ +#include <sys/stat.h> +#include <sys/statfs.h> + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "ficl.h" + +void *ficlMalloc(size_t size) +{ + return malloc(size); +} + +void *ficlRealloc(void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree(void *p) +{ + free(p); +} + +void ficlCallbackDefaultTextOut(ficlCallback *callback, char *message) +{ + FICL_IGNORE(callback); + if (message != NULL) + fputs(message, stdout); + else + fflush(stdout); + return; +} + +int ficlFileStatus(char *filename, int *status) +{ + struct stat statbuf; + if (stat(filename, &statbuf) == 0) + { + *status = statbuf.st_mode; + return 0; + } + *status = ENOENT; + return -1; +} + +long ficlFileSize(ficlFile *ff) +{ + struct stat statbuf; + if (ff == NULL) + return -1; + + statbuf.st_size = -1; + if (fstat(fileno(ff->f), &statbuf) != 0) + return -1; + + return statbuf.st_size; +} + +void ficlSystemCompilePlatform(ficlSystem *system) +{ + return; +} + + diff --git a/apps/interpreters/ficl/src/nuttx.h b/apps/interpreters/ficl/src/nuttx.h new file mode 100644 index 000000000..e44031066 --- /dev/null +++ b/apps/interpreters/ficl/src/nuttx.h @@ -0,0 +1,19 @@ +#include <stdint.h> + +typedef int8_t ficlInteger8; +typedef uint8_t ficlUnsigned8; +typedef int16_t ficlInteger16; +typedef uint16_t ficlUnsigned16; +typedef int32_t ficlInteger32; +typedef uint32_t ficlUnsigned32; + +typedef intptr_t ficlInteger; +typedef uintptr_t ficlUnsigned; +typedef float ficlFloat; + +#define FICL_PLATFORM_BASIC_TYPES (1) +#define FICL_PLATFORM_HAS_2INTEGER (0) +#define FICL_PLATFORM_HAS_FTRUNCATE (0) + +#define FICL_PLATFORM_OS "ansi" +#define FICL_PLATFORM_ARCHITECTURE "unknown" diff --git a/apps/namedapp/Makefile b/apps/namedapp/Makefile new file mode 100644 index 000000000..fba8fb1ff --- /dev/null +++ b/apps/namedapp/Makefile @@ -0,0 +1,106 @@ +############################################################################ +# apps/nshlib/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NSH Library + +# Source and object files + +ASRCS = +CSRCS = namedapp.c exec_namedapp.c + +ifeq ($(CONFIG_APPS_BINDIR),y) +CSRCS += binfs.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . +VPATH = + +# Build Targets + +all: .built +.PHONY: .context context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: + @echo "/* List of application requirements, generated during make context. */" > namedapp_list.h + @echo "/* List of application entry points, generated during make context. */" > namedapp_proto.h + @touch $@ + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f .context Make.dep .depend + @rm -f namedapp_list.h + @rm -f namedapp_proto.h + +-include Make.dep + diff --git a/apps/namedapp/binfs.c b/apps/namedapp/binfs.c new file mode 100644 index 000000000..106c1444c --- /dev/null +++ b/apps/namedapp/binfs.c @@ -0,0 +1,596 @@ +/**************************************************************************** + * apps/namedapps/binfs.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/statfs.h> +#include <sys/stat.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/fs.h> +#include <nuttx/dirent.h> + +#include "namedapp.h" + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_APPS_BINDIR) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure represents the overall mountpoint state. An instance of this + * structure is retained as inode private data on each mountpoint that is + * mounted with a fat32 filesystem. + */ + +struct binfs_state_s +{ + sem_t bm_sem; /* Used to assume thread-safe access */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void binfs_semtake(struct binfs_state_s *bm); +static inline void binfs_semgive(struct binfs_state_s *bm); +static int binfs_open(FAR struct file *filep, const char *relpath, + int oflags, mode_t mode); +static int binfs_close(FAR struct file *filep); +static ssize_t binfs_read(FAR struct file *filep, char *buffer, size_t buflen); +static int binfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +static int binfs_opendir(struct inode *mountpt, const char *relpath, + struct fs_dirent_s *dir); +static int binfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir); +static int binfs_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir); + +static int binfs_bind(FAR struct inode *blkdriver, const void *data, + void **handle); +static int binfs_unbind(void *handle, FAR struct inode **blkdriver); +static int binfs_statfs(struct inode *mountpt, struct statfs *buf); + +static int binfs_stat(struct inode *mountpt, const char *relpath, struct stat *buf); + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/* See fs_mount.c -- this structure is explicitly externed there. + * We use the old-fashioned kind of initializers so that this will compile + * with any compiler. + */ + +const struct mountpt_operations binfs_operations = +{ + binfs_open, /* open */ + binfs_close, /* close */ + binfs_read, /* read */ + NULL, /* write */ + NULL, /* seek */ + binfs_ioctl, /* ioctl */ + NULL, /* sync */ + + binfs_opendir, /* opendir */ + NULL, /* closedir */ + binfs_readdir, /* readdir */ + binfs_rewinddir, /* rewinddir */ + + binfs_bind, /* bind */ + binfs_unbind, /* unbind */ + binfs_statfs, /* statfs */ + + NULL, /* unlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* rename */ + binfs_stat /* stat */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: binfs_semtake + ****************************************************************************/ + +static void binfs_semtake(struct binfs_state_s *bm) +{ + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(&bm->bm_sem) != 0) + { + /* The only case that an error should occur here is if + * the wait was awakened by a signal. + */ + + ASSERT(errno == EINTR); + } +} + +/**************************************************************************** + * Name: binfs_semgive + ****************************************************************************/ + +static inline void binfs_semgive(struct binfs_state_s *bm) +{ + sem_post(&bm->bm_sem); +} + +/**************************************************************************** + * Name: binfs_open + ****************************************************************************/ + +static int binfs_open(FAR struct file *filep, const char *relpath, + int oflags, mode_t mode) +{ + struct binfs_state_s *bm; + int ret = -ENOSYS; + + fvdbg("Open '%s'\n", relpath); + + /* Sanity checks */ + + DEBUGASSERT(filep->f_priv == NULL && filep->f_inode != NULL); + + /* mountpoint private data from the inode reference from the file + * structure + */ + + bm = (struct binfs_state_s*)filep->f_inode->i_private; + DEBUGASSERT(bm != NULL); + + /* BINFS is read-only. Any attempt to open with any kind of write + * access is not permitted. + */ + + if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) + { + fdbg("Only O_RDONLY supported\n"); + ret = -EACCES; + } + + /* Save open-specific state in filep->f_priv */ + + /* Opening of elements within the pseudo-file system is not yet supported */ + + return ret; +} + +/**************************************************************************** + * Name: binfs_close + ****************************************************************************/ + +static int binfs_close(FAR struct file *filep) +{ + struct binfs_state_s *bm; + int ret = -ENOSYS; + + fvdbg("Closing\n"); + + /* Sanity checks */ + + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover the open file state from the struct file instance */ + /* bf = filep->f_priv; */ + + /* Recover the file system state from the inode */ + + bm = filep->f_inode->i_private; + DEBUGASSERT(bm != NULL); + + /* Free the open file state */ + /* free(bf); */ + + filep->f_priv = NULL; + + /* Since open() is not yet supported, neither is close(). */ + + return ret; +} + +/**************************************************************************** + * Name: binfs_read + ****************************************************************************/ + +static ssize_t binfs_read(FAR struct file *filep, char *buffer, size_t buflen) +{ + struct binfs_state_s *bm; + + fvdbg("Read %d bytes from offset %d\n", buflen, filep->f_pos); + + /* Sanity checks */ + + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover the open file state data from the struct file instance */ + /* bf = filep->f_priv; */ + + /* Recover the file system state from the inode */ + + bm = filep->f_inode->i_private; + DEBUGASSERT(bm != NULL); + + /* Since open is not yet supported, neither is reading */ + + return -ENOSYS; +} + +/**************************************************************************** + * Name: binfs_ioctl + ****************************************************************************/ + +static int binfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + struct binfs_state_s *bm; + + fvdbg("cmd: %d arg: %08lx\n", cmd, arg); + + /* Sanity checks */ + + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + + /* Recover the open file state from the struct file instance */ + /* bf = filep->f_priv; */ + + /* Recover the file system state from the inode */ + + bm = filep->f_inode->i_private; + DEBUGASSERT(bm != NULL); + + /* No ioctl commands yet supported */ + + return -ENOTTY; +} + +/**************************************************************************** + * Name: binfs_opendir + * + * Description: + * Open a directory for read access + * + ****************************************************************************/ + +static int binfs_opendir(struct inode *mountpt, const char *relpath, + struct fs_dirent_s *dir) +{ + struct binfs_state_s *bm; + int ret; + + fvdbg("relpath: \"%s\"\n", relpath ? relpath : "NULL"); + + /* Sanity checks */ + + DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); + + /* Recover the file system state from the inode instance */ + + bm = mountpt->i_private; + binfs_semtake(bm); + + /* The requested directory must be the volume-relative "root" directory */ + + if (relpath && relpath[0] != '\0') + { + ret = -ENOENT; + goto errout_with_semaphore; + } + + /* Set the index to the first entry */ + + dir->u.binfs.fb_index = 0; + ret = OK; + +errout_with_semaphore: + binfs_semgive(bm); + return ret; +} + +/**************************************************************************** + * Name: binfs_readdir + * + * Description: Read the next directory entry + * + ****************************************************************************/ + +static int binfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) +{ + struct binfs_state_s *bm; + unsigned int index; + int ret; + + /* Sanity checks */ + + DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); + + /* Recover the file system state from the inode instance */ + + bm = mountpt->i_private; + binfs_semtake(bm); + + /* Have we reached the end of the directory */ + + index = dir->u.binfs.fb_index; + if (namedapps[index].name == NULL) + { + /* We signal the end of the directory by returning the + * special error -ENOENT + */ + + fvdbg("Entry %d: End of directory\n", index); + ret = -ENOENT; + } + else + { + /* Save the filename and file type */ + + fvdbg("Entry %d: \"%s\"\n", index, namedapps[index].name); + dir->fd_dir.d_type = DTYPE_FILE; + strncpy(dir->fd_dir.d_name, namedapps[index].name, NAME_MAX+1); + + /* The application list is terminated by an entry with a NULL name. + * Therefore, there is at least one more entry in the list. + */ + + index++; + + /* Set up the next directory entry offset. NOTE that we could use the + * standard f_pos instead of our own private fb_index. + */ + + dir->u.binfs.fb_index = index; + ret = OK; + } + + binfs_semgive(bm); + return ret; +} + +/**************************************************************************** + * Name: binfs_rewindir + * + * Description: Reset directory read to the first entry + * + ****************************************************************************/ + +static int binfs_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir) +{ + struct binfs_state_s *bm; + + fvdbg("Entry\n"); + + /* Sanity checks */ + + DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL); + + /* Recover the file system state from the inode instance */ + + bm = mountpt->i_private; + binfs_semtake(bm); + + dir->u.binfs.fb_index = 0; + + binfs_semgive(bm); + return OK; +} + +/**************************************************************************** + * Name: binfs_bind + * + * Description: This implements a portion of the mount operation. This + * function allocates and initializes the mountpoint private data and + * binds the blockdriver inode to the filesystem private data. The final + * binding of the private data (containing the blockdriver) to the + * mountpoint is performed by mount(). + * + ****************************************************************************/ + +static int binfs_bind(FAR struct inode *blkdriver, const void *data, + void **handle) +{ + struct binfs_state_s *bm; + + fvdbg("Entry\n"); + + /* Create an instance of the mountpt state structure */ + + bm = (struct binfs_state_s *)zalloc(sizeof(struct binfs_state_s)); + if (!bm) + { + fdbg("Failed to allocate mountpoint structure\n"); + return -ENOMEM; + } + + /* Initialize the allocated mountpt state structure. The filesystem is + * responsible for one reference ont the blkdriver inode and does not + * have to addref() here (but does have to release in ubind(). + */ + + sem_init(&bm->bm_sem, 0, 1); /* Initialize the semaphore that controls access */ + + /* Mounted! */ + + *handle = (void*)bm; + return OK; +} + +/**************************************************************************** + * Name: binfs_unbind + * + * Description: This implements the filesystem portion of the umount + * operation. + * + ****************************************************************************/ + +static int binfs_unbind(void *handle, FAR struct inode **blkdriver) +{ + struct binfs_state_s *bm = (struct binfs_state_s*)handle; + + fvdbg("Entry\n"); + +#ifdef CONFIG_DEBUG + if (!bm) + { + return -EINVAL; + } +#endif + + /* Check if there are sill any files opened on the filesystem. */ + + /* Release the mountpoint private data */ + + sem_destroy(&bm->bm_sem); + return OK; +} + +/**************************************************************************** + * Name: binfs_statfs + * + * Description: Return filesystem statistics + * + ****************************************************************************/ + +static int binfs_statfs(struct inode *mountpt, struct statfs *buf) +{ + struct binfs_state_s *bm; + + fvdbg("Entry\n"); + + /* Sanity checks */ + + DEBUGASSERT(mountpt && mountpt->i_private); + + /* Get the mountpoint private data from the inode structure */ + + bm = mountpt->i_private; + binfs_semtake(bm); + + /* Fill in the statfs info */ + + memset(buf, 0, sizeof(struct statfs)); + buf->f_type = BINFS_MAGIC; + buf->f_bsize = 0; + buf->f_blocks = 0; + buf->f_bfree = 0; + buf->f_bavail = 0; + buf->f_namelen = NAME_MAX; + + binfs_semgive(bm); + return OK; +} + +/**************************************************************************** + * Name: binfs_stat + * + * Description: Return information about a file or directory + * + ****************************************************************************/ + +static int binfs_stat(struct inode *mountpt, const char *relpath, struct stat *buf) +{ + struct binfs_state_s *bm; + int ret; + + fvdbg("Entry\n"); + + /* Sanity checks */ + + DEBUGASSERT(mountpt && mountpt->i_private); + + /* Get the mountpoint private data from the inode structure */ + + bm = mountpt->i_private; + binfs_semtake(bm); + + /* The requested directory must be the volume-relative "root" directory */ + + if (relpath && relpath[0] != '\0') + { + /* Check if there is a file with this name. */ + + if (namedapp_isavail(relpath) < 0) + { + ret = -ENOENT; + goto errout_with_semaphore; + } + + /* It's a execute-only file name */ + + buf->st_mode = S_IFREG|S_IXOTH|S_IXGRP|S_IXUSR; + } + else + { + /* It's a read/execute-only directory name */ + + buf->st_mode = S_IFDIR|S_IROTH|S_IRGRP|S_IRUSR|S_IXOTH|S_IXGRP|S_IXUSR; + } + + /* File/directory size, access block size */ + + buf->st_size = 0; + buf->st_blksize = 0; + buf->st_blocks = 0; + ret = OK; + +errout_with_semaphore: + binfs_semgive(bm); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_APPS_BINDIR */ + diff --git a/apps/namedapp/exec_namedapp.c b/apps/namedapp/exec_namedapp.c new file mode 100644 index 000000000..dd0f0b84f --- /dev/null +++ b/apps/namedapp/exec_namedapp.c @@ -0,0 +1,122 @@ +/**************************************************************************** + * apps/namedaps/exec_namedapp.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise <uros.platise@isotel.eu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <apps/apps.h> +#include <sched.h> + +#include <string.h> +#include <errno.h> + +#include "namedapp.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +const char *namedapp_getname(int index) +{ + if (index < 0 || index >= number_namedapps()) + { + return NULL; + } + + return namedapps[index].name; +} + +int namedapp_isavail(FAR const char *appname) +{ + int i; + + for (i = 0; namedapps[i].name; i++) + { + if (!strcmp(namedapps[i].name, appname)) + { + return i; + } + } + + set_errno(ENOENT); + return ERROR; +} + +int exec_namedapp(FAR const char *appname, FAR const char **argv) +{ + int i; + + if ((i = namedapp_isavail(appname)) >= 0) + { +#ifndef CONFIG_CUSTOM_STACK + i = task_create(namedapps[i].name, namedapps[i].priority, + namedapps[i].stacksize, namedapps[i].main, + (argv) ? &argv[1] : (const char **)NULL); +#else + i = task_create(namedapps[i].name, namedapps[i].priority, namedapps[i].main, + (argv) ? &argv[1] : (const char **)NULL); +#endif + +#if CONFIG_RR_INTERVAL > 0 + if (i > 0) + { + struct sched_param param; + + sched_getparam(0, ¶m); + sched_setscheduler(i, SCHED_RR, ¶m); + } +#endif + } + + return i; +} diff --git a/apps/namedapp/namedapp.c b/apps/namedapp/namedapp.c new file mode 100644 index 000000000..a5c2bee0e --- /dev/null +++ b/apps/namedapp/namedapp.c @@ -0,0 +1,96 @@ +/**************************************************************************** + * apps/namedaps/namedapp.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Authors: Uros Platise <uros.platise@isotel.eu> + * Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <apps/apps.h> + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +#include "namedapp_proto.h" + +const struct namedapp_s namedapps[] = +{ +# include "namedapp_list.h" + { NULL, 0, 0, 0 } +}; + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int number_namedapps(void) +{ + return sizeof(namedapps)/sizeof(struct namedapp_s) - 1; +} + + diff --git a/apps/namedapp/namedapp.h b/apps/namedapp/namedapp.h new file mode 100644 index 000000000..88fa7f36a --- /dev/null +++ b/apps/namedapp/namedapp.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * apps/namedaps/namedapp.h + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Authors: Uros Platise <uros.platise@isotel.eu> + * Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NAMEDAPP_NAMEDAPP_H +#define __APPS_NAMEDAPP_NAMEDAPP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <apps/apps.h> + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +EXTERN const struct namedapp_s namedapps[]; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +EXTERN int number_namedapps(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __APPS_NAMEDAPP_NAMEDAPP_H */ + diff --git a/apps/netutils/Makefile b/apps/netutils/Makefile new file mode 100644 index 000000000..df61f97e8 --- /dev/null +++ b/apps/netutils/Makefile @@ -0,0 +1,64 @@ +############################################################################ +# apps/netutils/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration + +# Sub-directories + +ifeq ($(CONFIG_NET),y) +SUBDIRS = uiplib dhcpc dhcpd ftpc resolv smtp telnetd webclient webserver tftpc thttpd +endif + +all: nothing +.PHONY: nothing context depend clean distclean + +nothing: + +context: + +depend: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir depend TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +clean: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +distclean: clean + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir distclean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done diff --git a/apps/netutils/README.txt b/apps/netutils/README.txt new file mode 100644 index 000000000..2059b569e --- /dev/null +++ b/apps/netutils/README.txt @@ -0,0 +1,40 @@ +netutils +^^^^^^^^ + +This directory contains most of the network applications contained +under the uIP-1.0 apps directory. As the uIP apps/README says, +these applications "are not all heavily tested." These uIP apps +include: + + dhcpc - Dynamic Host Configuration Protocol (DHCP) client + resolv - uIP DNS resolver + smtp - Simple Mail Transfer Protocol (SMTP) client + telnetd - TELNET server + webclient - HTTP web client + webserver - HTTP web server + +You may find additional information on these apps in the uIP forum +accessible through: http://www.sics.se/~adam/uip/index.php/Main_Page + +Additional applications that were not part of uIP (but which are +highly influenced by uIP) include: + + dhcpd - Dynamic Host Configuration Protocol (DHCP) server + tftpc - TFTP client + ftpc - FTP client + thttpd - This is a port of Jef Poskanzer's THTTPD HTPPD server. + See http://acme.com/software/thttpd/. + +If you use DHCPC/D, then some special configuration network options are +required. These include: + + CONFIG_NET=y Of course + CONFIG_NSOCKET_DESCRIPTORS And, of course, you must allocate some + socket descriptors. + CONFIG_NET_UDP=y UDP support is required for DHCP + (as well as various other UDP-related + configuration settings). + CONFIG_NET_BROADCAST=y UDP broadcast support is needed. + CONFIG_NET_BUFSIZE=650 The client must be prepared to receive + (or larger) DHCP messages of up to 576 bytes (excluding + Ethernet, IP, or UDP headers and FCS). diff --git a/apps/netutils/dhcpc/Makefile b/apps/netutils/dhcpc/Makefile new file mode 100644 index 000000000..d5f1f90c5 --- /dev/null +++ b/apps/netutils/dhcpc/Makefile @@ -0,0 +1,97 @@ +############################################################################ +# apps/netutils/dhcpc/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# DHCP Client Library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_UDP),y) +CSRCS += dhcpc.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/dhcpc/dhcpc.c b/apps/netutils/dhcpc/dhcpc.c new file mode 100644 index 000000000..b5551c6f1 --- /dev/null +++ b/apps/netutils/dhcpc/dhcpc.c @@ -0,0 +1,607 @@ +/**************************************************************************** + * netutils/dhcpc/dhcpc.c + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based heavily on portions of uIP: + * + * Author: Adam Dunkels <adam@dunkels.com> + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <errno.h> +#include <debug.h> + +#include <net/uip/uip.h> +#include <apps/netutils/dhcpc.h> +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define STATE_INITIAL 0 +#define STATE_HAVE_OFFER 1 +#define STATE_HAVE_LEASE 2 + +#define BOOTP_BROADCAST 0x8000 + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 +#define DHCP_MSG_LEN 236 + +#define DHCPC_SERVER_PORT 67 +#define DHCPC_CLIENT_PORT 68 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_REQ_IPADDR 50 +#define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_MSG_TYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_REQ_LIST 55 +#define DHCP_OPTION_END 255 + +#define BUFFER_SIZE 256 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct dhcp_msg +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint8_t xid[4]; + uint16_t secs; + uint16_t flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[16]; +#ifndef CONFIG_NET_DHCP_LIGHT + uint8_t sname[64]; + uint8_t file[128]; +#endif + uint8_t options[312]; +}; + +struct dhcpc_state_s +{ + struct uip_udp_conn *ds_conn; + const void *ds_macaddr; + int ds_maclen; + int sockfd; + struct in_addr ipaddr; + struct in_addr serverid; + struct dhcp_msg packet; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23}; +static const uint8_t magic_cookie[4] = {99, 130, 83, 99}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dhcpc_add<option> + ****************************************************************************/ + +static uint8_t *dhcpc_addmsgtype(uint8_t *optptr, uint8_t type) +{ + *optptr++ = DHCP_OPTION_MSG_TYPE; + *optptr++ = 1; + *optptr++ = type; + return optptr; +} + +static uint8_t *dhcpc_addserverid(struct in_addr *serverid, uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_SERVER_ID; + *optptr++ = 4; + memcpy(optptr, &serverid->s_addr, 4); + return optptr + 4; +} + +static uint8_t *dhcpc_addreqipaddr(struct in_addr *ipaddr, uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_REQ_IPADDR; + *optptr++ = 4; + memcpy(optptr, &ipaddr->s_addr, 4); + return optptr + 4; +} + +static uint8_t *dhcpc_addreqoptions(uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_REQ_LIST; + *optptr++ = 3; + *optptr++ = DHCP_OPTION_SUBNET_MASK; + *optptr++ = DHCP_OPTION_ROUTER; + *optptr++ = DHCP_OPTION_DNS_SERVER; + return optptr; +} + +static uint8_t *dhcpc_addend(uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_END; + return optptr; +} + +/**************************************************************************** + * Name: dhcpc_sendmsg + ****************************************************************************/ + +static int dhcpc_sendmsg(struct dhcpc_state_s *pdhcpc, + struct dhcpc_state *presult, int msgtype) +{ + struct sockaddr_in addr; + uint8_t *pend; + in_addr_t serverid = INADDR_BROADCAST; + int len; + + /* Create the common message header settings */ + + memset(&pdhcpc->packet, 0, sizeof(struct dhcp_msg)); + pdhcpc->packet.op = DHCP_REQUEST; + pdhcpc->packet.htype = DHCP_HTYPE_ETHERNET; + pdhcpc->packet.hlen = pdhcpc->ds_maclen; + memcpy(pdhcpc->packet.xid, xid, 4); + memcpy(pdhcpc->packet.chaddr, pdhcpc->ds_macaddr, pdhcpc->ds_maclen); + memset(&pdhcpc->packet.chaddr[pdhcpc->ds_maclen], 0, 16 - pdhcpc->ds_maclen); + memcpy(pdhcpc->packet.options, magic_cookie, sizeof(magic_cookie)); + + /* Add the common header options */ + + pend = &pdhcpc->packet.options[4]; + pend = dhcpc_addmsgtype(pend, msgtype); + + /* Handle the message specific settings */ + + switch (msgtype) + { + /* Broadcast DISCOVER message to all servers */ + + case DHCPDISCOVER: + pdhcpc->packet.flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */ + pend = dhcpc_addreqoptions(pend); + break; + + /* Send REQUEST message to the server that sent the *first* OFFER */ + + case DHCPREQUEST: + pdhcpc->packet.flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */ + memcpy(pdhcpc->packet.ciaddr, &pdhcpc->ipaddr.s_addr, 4); + pend = dhcpc_addserverid(&pdhcpc->serverid, pend); + pend = dhcpc_addreqipaddr(&pdhcpc->ipaddr, pend); + break; + + /* Send DECLINE message to the server that sent the *last* OFFER */ + + case DHCPDECLINE: + memcpy(pdhcpc->packet.ciaddr, &presult->ipaddr.s_addr, 4); + pend = dhcpc_addserverid(&presult->serverid, pend); + serverid = presult->serverid.s_addr; + break; + + default: + return ERROR; + } + + pend = dhcpc_addend(pend); + len = pend - (uint8_t*)&pdhcpc->packet; + + /* Send the request */ + + addr.sin_family = AF_INET; + addr.sin_port = HTONS(DHCPC_SERVER_PORT); + addr.sin_addr.s_addr = serverid; + + return sendto(pdhcpc->sockfd, &pdhcpc->packet, len, 0, + (struct sockaddr*)&addr, sizeof(struct sockaddr_in)); +} + +/**************************************************************************** + * Name: dhcpc_parseoptions + ****************************************************************************/ + +static uint8_t dhcpc_parseoptions(struct dhcpc_state *presult, uint8_t *optptr, int len) +{ + uint8_t *end = optptr + len; + uint8_t type = 0; + + while (optptr < end) + { + switch(*optptr) + { + case DHCP_OPTION_SUBNET_MASK: + /* Get subnet mask in network order */ + + memcpy(&presult->netmask.s_addr, optptr + 2, 4); + break; + + case DHCP_OPTION_ROUTER: + /* Get the default router address in network order */ + + memcpy(&presult->default_router.s_addr, optptr + 2, 4); + break; + + case DHCP_OPTION_DNS_SERVER: + /* Get the DNS server address in network order */ + + memcpy(&presult->dnsaddr.s_addr, optptr + 2, 4); + break; + + case DHCP_OPTION_MSG_TYPE: + /* Get message type */ + + type = *(optptr + 2); + break; + + case DHCP_OPTION_SERVER_ID: + /* Get server address in network order */ + + memcpy(&presult->serverid.s_addr, optptr + 2, 4); + break; + + case DHCP_OPTION_LEASE_TIME: + { + /* Get lease time (in seconds) in host order */ + + uint16_t tmp[2]; + memcpy(tmp, optptr + 2, 4); + presult->lease_time = ((uint32_t)ntohs(tmp[0])) << 16 | (uint32_t)ntohs(tmp[1]); + } + break; + + case DHCP_OPTION_END: + return type; + } + + optptr += optptr[1] + 2; + } + return type; +} + +/**************************************************************************** + * Name: dhcpc_parsemsg + ****************************************************************************/ + +static uint8_t dhcpc_parsemsg(struct dhcpc_state_s *pdhcpc, int buflen, + struct dhcpc_state *presult) +{ + if (pdhcpc->packet.op == DHCP_REPLY && + memcmp(pdhcpc->packet.xid, xid, sizeof(xid)) == 0 && + memcmp(pdhcpc->packet.chaddr, pdhcpc->ds_macaddr, pdhcpc->ds_maclen) == 0) + { + memcpy(&presult->ipaddr.s_addr, pdhcpc->packet.yiaddr, 4); + return dhcpc_parseoptions(presult, &pdhcpc->packet.options[4], buflen); + } + return 0; +} + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dhcpc_open + ****************************************************************************/ + +void *dhcpc_open(const void *macaddr, int maclen) +{ + struct dhcpc_state_s *pdhcpc; + struct sockaddr_in addr; + struct timeval tv; + + dbg("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + ((uint8_t*)macaddr)[0], ((uint8_t*)macaddr)[1], ((uint8_t*)macaddr)[2], + ((uint8_t*)macaddr)[3], ((uint8_t*)macaddr)[4], ((uint8_t*)macaddr)[5]); + + /* Allocate an internal DHCP structure */ + + pdhcpc = (struct dhcpc_state_s *)malloc(sizeof(struct dhcpc_state_s)); + if (pdhcpc) + { + /* Initialize the allocated structure */ + + memset(pdhcpc, 0, sizeof(struct dhcpc_state_s)); + pdhcpc->ds_macaddr = macaddr; + pdhcpc->ds_maclen = maclen; + + /* Create a UDP socket */ + + pdhcpc->sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (pdhcpc->sockfd < 0) + { + free(pdhcpc); + return NULL; + } + + /* bind the socket */ + + addr.sin_family = AF_INET; + addr.sin_port = HTONS(DHCPC_CLIENT_PORT); + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(pdhcpc->sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) + { + close(pdhcpc->sockfd); + free(pdhcpc); + return NULL; + } + + /* Configure for read timeouts */ + + tv.tv_sec = 10; + tv.tv_usec = 0; + if (setsockopt(pdhcpc->sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) < 0) + { + close(pdhcpc->sockfd); + free(pdhcpc); + return NULL; + } + } + + return (void*)pdhcpc; +} + +/**************************************************************************** + * Name: dhcpc_close + ****************************************************************************/ + +void dhcpc_close(void *handle) +{ + struct dchcpc_state_internal *pdhcpc = (struct dchcpc_state_internal *)handle; + if (pdhcpc) + { + free(pdhcpc); + } +} + +/**************************************************************************** + * Name: dhcpc_request + ****************************************************************************/ + +int dhcpc_request(void *handle, struct dhcpc_state *presult) +{ + struct dhcpc_state_s *pdhcpc = (struct dhcpc_state_s *)handle; + struct in_addr oldaddr; + struct in_addr newaddr; + ssize_t result; + uint8_t msgtype; + int retries; + int state; + + /* Save the currently assigned IP address (should be INADDR_ANY) */ + + oldaddr.s_addr = 0; + uip_gethostaddr("eth0", &oldaddr); + + /* Loop until we receive the lease (or an error occurs) */ + + do + { + /* Set the IP address to INADDR_ANY. */ + + newaddr.s_addr = INADDR_ANY; + (void)uip_sethostaddr("eth0", &newaddr); + + /* Loop sending DISCOVER until we receive an OFFER from a DHCP + * server. We will lock on to the first OFFER and decline any + * subsequent offers (which will happen if there are more than one + * DHCP servers on the network. + */ + + state = STATE_INITIAL; + do + { + /* Send the DISCOVER command */ + + dbg("Broadcast DISCOVER\n"); + if (dhcpc_sendmsg(pdhcpc, presult, DHCPDISCOVER) < 0) + { + return ERROR; + } + + /* Get the DHCPOFFER response */ + + result = recv(pdhcpc->sockfd, &pdhcpc->packet, sizeof(struct dhcp_msg), 0); + if (result >= 0) + { + msgtype = dhcpc_parsemsg(pdhcpc, result, presult); + if (msgtype == DHCPOFFER) + { + /* Save the servid from the presult so that it is not clobbered + * by a new OFFER. + */ + + dbg("Received OFFER from %08x\n", ntohl(presult->serverid.s_addr)); + pdhcpc->ipaddr.s_addr = presult->ipaddr.s_addr; + pdhcpc->serverid.s_addr = presult->serverid.s_addr; + + /* Temporarily use the address offered by the server and break + * out of the loop. + */ + + (void)uip_sethostaddr("eth0", &presult->ipaddr); + state = STATE_HAVE_OFFER; + } + } + + /* An error has occurred. If this was a timeout error (meaning that + * nothing was received on this socket for a long period of time). + * Then loop and send the DISCOVER command again. + */ + + else if (errno != EAGAIN) + { + /* An error other than a timeout was received -- error out */ + + return ERROR; + } + } + while (state == STATE_INITIAL); + + + /* Loop sending the REQUEST up to three times (if there is no response) */ + + retries = 0; + do + { + /* Send the REQUEST message to obtain the lease that was offered to us. */ + + dbg("Send REQUEST\n"); + if (dhcpc_sendmsg(pdhcpc, presult, DHCPREQUEST) < 0) + { + return ERROR; + } + retries++; + + /* Get the ACK/NAK response to the REQUEST (or timeout) */ + + result = recv(pdhcpc->sockfd, &pdhcpc->packet, sizeof(struct dhcp_msg), 0); + if (result >= 0) + { + /* Parse the response */ + + msgtype = dhcpc_parsemsg(pdhcpc, result, presult); + + /* The ACK response means that the server has accepted our request + * and we have the lease. + */ + + if (msgtype == DHCPACK) + { + dbg("Received ACK\n"); + state = STATE_HAVE_LEASE; + } + + /* NAK means the server has refused our request. Break out of + * this loop with state == STATE_HAVE_OFFER and send DISCOVER again + */ + + else if (msgtype == DHCPNAK) + { + dbg("Received NAK\n"); + break; + } + + /* If we get any OFFERs from other servers, then decline them now + * and continue waiting for the ACK from the server that we + * requested from. + */ + + else if (msgtype == DHCPOFFER) + { + dbg("Received another OFFER, send DECLINE\n"); + (void)dhcpc_sendmsg(pdhcpc, presult, DHCPDECLINE); + } + + /* Otherwise, it is something that we do not recognize */ + + else + { + dbg("Ignoring msgtype=%d\n", msgtype); + } + } + + /* An error has occurred. If this was a timeout error (meaning + * that nothing was received on this socket for a long period of time). + * Then break out and send the DISCOVER command again (at most + * 3 times). + */ + + else if (errno != EAGAIN) + { + /* An error other than a timeout was received */ + + (void)uip_sethostaddr("eth0", &oldaddr); + return ERROR; + } + } + while (state == STATE_HAVE_OFFER && retries < 3); + } + while (state != STATE_HAVE_LEASE); + + dbg("Got IP address %d.%d.%d.%d\n", + (presult->ipaddr.s_addr >> 24 ) & 0xff, + (presult->ipaddr.s_addr >> 16 ) & 0xff, + (presult->ipaddr.s_addr >> 8 ) & 0xff, + (presult->ipaddr.s_addr ) & 0xff); + dbg("Got netmask %d.%d.%d.%d\n", + (presult->netmask.s_addr >> 24 ) & 0xff, + (presult->netmask.s_addr >> 16 ) & 0xff, + (presult->netmask.s_addr >> 8 ) & 0xff, + (presult->netmask.s_addr ) & 0xff); + dbg("Got DNS server %d.%d.%d.%d\n", + (presult->dnsaddr.s_addr >> 24 ) & 0xff, + (presult->dnsaddr.s_addr >> 16 ) & 0xff, + (presult->dnsaddr.s_addr >> 8 ) & 0xff, + (presult->dnsaddr.s_addr ) & 0xff); + dbg("Got default router %d.%d.%d.%d\n", + (presult->default_router.s_addr >> 24 ) & 0xff, + (presult->default_router.s_addr >> 16 ) & 0xff, + (presult->default_router.s_addr >> 8 ) & 0xff, + (presult->default_router.s_addr ) & 0xff); + dbg("Lease expires in %d seconds\n", presult->lease_time); + return OK; +} diff --git a/apps/netutils/dhcpd/Makefile b/apps/netutils/dhcpd/Makefile new file mode 100644 index 000000000..b05fe1c74 --- /dev/null +++ b/apps/netutils/dhcpd/Makefile @@ -0,0 +1,97 @@ +############################################################################ +# apps/netutils/dhcpd/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <gnutt@nuttx.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# DHCP Daemn Library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_UDP),y) +CSRCS += dhcpd.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/dhcpd/dhcpd.c b/apps/netutils/dhcpd/dhcpd.c new file mode 100644 index 000000000..66bf76f81 --- /dev/null +++ b/apps/netutils/dhcpd/dhcpd.c @@ -0,0 +1,1433 @@ +/**************************************************************************** + * netutils/dhcpd/dhcpd.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifdef CONFIG_NETUTILS_DHCPD_HOST +# include <stdio.h> + +# define HTONS(a) htons(a) +# define HTONL(a) htonl(a) + +# define CONFIG_CPP_HAVE_WARNING 1 +# define FAR + +# define ndbg(...) printf(__VA_ARGS__) +# define nvdbg(...) printf(__VA_ARGS__) + +# define ERROR (-1) +# define OK (0) +#else +# include <nuttx/config.h> /* NuttX configuration */ +# include <debug.h> /* For ndbg, vdbg */ +# include <nuttx/compiler.h> /* For CONFIG_CPP_HAVE_WARNING */ +# include <arch/irq.h> /* For irqstore() and friends -- REVISIT */ +# include <net/uip/uip-arp.h> /* For low-level ARP interfaces -- REVISIT */ +# include <apps/netutils/dhcpd.h> /* Advertised DHCPD APIs */ +#endif + +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <errno.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#define DHCP_SERVER_PORT 67 +#define DHCP_CLIENT_PORT 68 + +/* Option codes understood in this file */ +/* Code Data Description */ +/* Length */ +#define DHCP_OPTION_PAD 1 /* 1 Pad */ +#define DHCP_OPTION_REQ_IPADDR 50 /* 4 Requested IP Address */ +#define DHCP_OPTION_LEASE_TIME 51 /* 4 IP address lease time */ +#define DHCP_OPTION_OVERLOAD 52 /* 1 Option overload */ +#define DHCP_OPTION_MSG_TYPE 53 /* 1 DHCP message type */ +#define DHCP_OPTION_SERVER_ID 54 /* 4 Server identifier */ +#define DHCP_OPTION_END 255 /* 0 End */ + +/* Values for the dhcp msg 'op' field */ + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 + +/* DHCP message types understood in this file */ + +#define DHCPDISCOVER 1 /* Received from client only */ +#define DHCPOFFER 2 /* Sent from server only */ +#define DHCPREQUEST 3 /* Received from client only */ +#define DHCPDECLINE 4 /* Received from client only */ +#define DHCPACK 5 /* Sent from server only */ +#define DHCPNAK 6 /* Sent from server only */ +#define DHCPRELEASE 7 /* Received from client only */ +#define DHCPINFORM 8 /* Not used */ + +/* The form of an option is: + * code - 1 byte + * length - 1 byte + * data - variable number of bytes + */ + +#define DHCPD_OPTION_CODE 0 +#define DHCPD_OPTION_LENGTH 1 +#define DHCPD_OPTION_DATA 2 + +/* Size of options in DHCP message */ + +#define DHCPD_OPTIONS_SIZE 312 + +/* Values for htype and hlen field */ + +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 + +/* Values for flags field */ + +#define BOOTP_BROADCAST 0x8000 + +/* Legal values for this option are: + * + * 1 the 'file' field is used to hold options + * 2 the 'sname' field is used to hold options + * 3 both fields are used to hold options + */ + +#define DHCPD_OPTION_FIELD 0 +#define DHCPD_FILE_FIELD 1 +#define DHCPD_SNAME_FIELD 2 + +#ifndef CONFIG_NETUTILS_DHCPD_LEASETIME +# define CONFIG_NETUTILS_DHCPD_LEASETIME (60*60*24*10) /* 10 days */ +# undef CONFIG_NETUTILS_DHCPD_MINLEASETIME +# undef CONFIG_NETUTILS_DHCPD_MAXLEASETIME +#endif + +#ifndef CONFIG_NETUTILS_DHCPD_MINLEASETIME +# define CONFIG_NETUTILS_DHCPD_MINLEASETIME (60*60*24*1) /* 1 days */ +#endif + +#ifndef CONFIG_NETUTILS_DHCPD_MAXLEASETIME +# define CONFIG_NETUTILS_DHCPD_MAXLEASETIME (60*60*24*30) /* 30 days */ +#endif + +#ifndef CONFIG_NETUTILS_DHCPD_INTERFACE +# define CONFIG_NETUTILS_DHCPD_INTERFACE "eth0" +#endif + +#ifndef CONFIG_NETUTILS_DHCPD_MAXLEASES +# define CONFIG_NETUTILS_DHCPD_MAXLEASES 16 +#endif + +#ifndef CONFIG_NETUTILS_DHCPD_STARTIP +# define CONFIG_NETUTILS_DHCPD_STARTIP (10L<<24|0L<<16|0L<<16|2L) +#endif + +#undef CONFIG_NETUTILS_DHCP_OPTION_ENDIP +#define CONFIG_NETUTILS_DHCP_OPTION_ENDIP \ + (CONFIG_NETUTILS_DHCPD_STARTIP + CONFIG_NETUTILS_DHCPD_MAXLEASES - 1) + +#ifndef CONFIG_NETUTILS_DHCPD_OFFERTIME +# define CONFIG_NETUTILS_DHCPD_OFFERTIME (60*60) /* 1 hour */ +#endif + +#ifndef CONFIG_NETUTILS_DHCPD_DECLINETIME +# define CONFIG_NETUTILS_DHCPD_DECLINETIME (60*60) /* 1 hour */ +#endif + +#undef HAVE_LEASE_TIME +#if defined(CONFIG_NETUTILS_DHCPD_HOST) || !defined(CONFIG_DISABLE_POSIX_TIMERS) +# define HAVE_LEASE_TIME 1 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes one element in the lease table. There is one slot + * in the lease table for each assign-able IP address (hence, the IP address + * itself does not have to be in the table. + */ + +struct lease_s +{ + uint8_t mac[DHCP_HLEN_ETHERNET]; /* MAC address (network order) -- could be larger! */ + bool allocated; /* true: IP address is allocated */ +#ifdef HAVE_LEASE_TIME + time_t expiry; /* Lease expiration time (seconds past Epoch) */ +#endif +}; + +struct dhcpmsg_s +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint8_t xid[4]; + uint16_t secs; + uint16_t flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[16]; +#ifndef CONFIG_NET_DHCP_LIGHT + uint8_t sname[64]; + uint8_t file[128]; +#endif + uint8_t options[312]; +}; + +struct dhcpd_state_s +{ + /* Server configuration */ + + in_addr_t ds_serverip; /* The server IP address */ + + /* Message buffers */ + + struct dhcpmsg_s ds_inpacket; /* Holds the incoming DHCP client message */ + struct dhcpmsg_s ds_outpacket; /* Holds the outgoing DHCP server message */ + + /* Parsed options from the incoming DHCP client message */ + + uint8_t ds_optmsgtype; /* Incoming DHCP message type */ + in_addr_t ds_optreqip; /* Requested IP address (host order) */ + in_addr_t ds_optserverip; /* Serverip IP address (host order) */ + time_t ds_optleasetime; /* Requested lease time (host order) */ + + /* End option pointer for outgoing DHCP server message */ + + uint8_t *ds_optend; + + /* Leases */ + + struct lease_s ds_leases[CONFIG_NETUTILS_DHCPD_MAXLEASES]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint8_t g_magiccookie[4] = {99, 130, 83, 99}; +static const uint8_t g_anyipaddr[4] = {0, 0, 0, 0}; +static struct dhcpd_state_s g_state; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dhcpd_arpupdate + ****************************************************************************/ + +#ifndef CONFIG_NETUTILS_DHCPD_HOST +static inline void dhcpd_arpupdate(uint16_t *pipaddr, uint8_t *phwaddr) +{ + uip_lock_t flags; + + /* Disable interrupts and update the ARP table -- very non-portable hack. + * REVISIT -- switch to the SIOCSARP ioctl call if/when it is implemented. + */ + + flags = uip_lock(); + uip_arp_update(pipaddr, phwaddr); + uip_unlock(flags); +} +#else +# define dhcpd_arpupdate(pipaddr,phwaddr) +#endif + +/**************************************************************************** + * Name: dhcpd_time + ****************************************************************************/ + +#ifdef CONFIG_NETUTILS_DHCPD_HOST +# define dhcpd_time() time(0) +#elif defined(HAVE_LEASE_TIME) +static time_t dhcpd_time(void) +{ + struct timespec ts; + time_t ret = 0; + + if (clock_gettime(CLOCK_REALTIME, &ts) == OK) + { + ret = ts.tv_sec; + } + return ret; +} +#else +# define dhcpd_time() (0) +#endif + +/**************************************************************************** + * Name: dhcpd_leaseexpired + ****************************************************************************/ + +#ifdef HAVE_LEASE_TIME +static inline bool dhcpd_leaseexpired(struct lease_s *lease) +{ + if (lease->expiry < dhcpd_time()) + { + return false; + } + else + { + memset(lease, 0, sizeof(struct lease_s)); + return true; + } +} +#else +# define dhcpd_leaseexpired(lease) (false) +#endif + +/**************************************************************************** + * Name: dhcpd_setlease + ****************************************************************************/ + +struct lease_s *dhcpd_setlease(const uint8_t *mac, in_addr_t ipaddr, time_t expiry) +{ + /* Calculate the offset from the first IP address managed by DHCPD. + * ipaddr must be in host order! + */ + + int ndx = ipaddr - CONFIG_NETUTILS_DHCPD_STARTIP; + struct lease_s *ret = NULL; + + nvdbg("ipaddr: %08x ipaddr: %08x ndx: %d MAX: %d\n", + ipaddr, CONFIG_NETUTILS_DHCPD_STARTIP, ndx, + CONFIG_NETUTILS_DHCPD_MAXLEASES); + + /* Verify that the address offset is within the supported range */ + + if (ndx >= 0 && ndx < CONFIG_NETUTILS_DHCPD_MAXLEASES) + { + ret = &g_state.ds_leases[ndx]; + memcpy(ret->mac, mac, DHCP_HLEN_ETHERNET); + ret->allocated = true; +#ifdef HAVE_LEASE_TIME + ret->expiry = dhcpd_time() + expiry; +#endif + } + + return ret; +} + +/**************************************************************************** + * Name: dhcp_leaseipaddr + ****************************************************************************/ + +static inline in_addr_t dhcp_leaseipaddr( struct lease_s *lease) +{ + /* Return IP address in host order */ + + return (g_state.ds_leases - lease)/sizeof(struct lease_s) + CONFIG_NETUTILS_DHCPD_STARTIP; +} + +/**************************************************************************** + * Name: dhcpd_findbymac + ****************************************************************************/ + +static struct lease_s *dhcpd_findbymac(const uint8_t *mac) +{ + int i; + + for (i = 0; i < CONFIG_NETUTILS_DHCPD_MAXLEASES; i++) + { + if (memcmp(g_state.ds_leases[i].mac, mac, DHCP_HLEN_ETHERNET) == 0) + { + return &(g_state.ds_leases[i]); + } + } + + return NULL; +} + +/**************************************************************************** + * Name: dhcpd_findbyipaddr + ****************************************************************************/ + +static struct lease_s *dhcpd_findbyipaddr(in_addr_t ipaddr) +{ + if (ipaddr >= CONFIG_NETUTILS_DHCPD_STARTIP && + ipaddr <= CONFIG_NETUTILS_DHCP_OPTION_ENDIP) + { + struct lease_s *lease = &g_state.ds_leases[ipaddr - CONFIG_NETUTILS_DHCPD_STARTIP]; + if (lease->allocated > 0) + { + return lease; + } + } + return NULL; +} + +/**************************************************************************** + * Name: dhcpd_allocipaddr + ****************************************************************************/ + +in_addr_t dhcpd_allocipaddr(void) +{ + struct lease_s *lease = NULL; + in_addr_t ipaddr; + + ipaddr = CONFIG_NETUTILS_DHCPD_STARTIP; + for (; ipaddr <= CONFIG_NETUTILS_DHCP_OPTION_ENDIP; ipaddr++) + { + if ((ipaddr & 0xff) == 0 || (ipaddr & 0xff) == 0xff) + { + continue; + } + + lease = dhcpd_findbyipaddr(ipaddr); + if ((!lease || dhcpd_leaseexpired(lease))) + { +#ifdef CONFIG_CPP_HAVE_WARNING +# warning "FIXME: Should check if anything responds to an ARP request or ping" +# warning " to verify that there is no other user of this IP address" +#endif + memset(g_state.ds_leases[ipaddr - CONFIG_NETUTILS_DHCPD_STARTIP].mac, 0, DHCP_HLEN_ETHERNET); + g_state.ds_leases[ipaddr - CONFIG_NETUTILS_DHCPD_STARTIP].allocated = true; +#ifdef HAVE_LEASE_TIME + g_state.ds_leases[ipaddr - CONFIG_NETUTILS_DHCPD_STARTIP].expiry = dhcpd_time() + CONFIG_NETUTILS_DHCPD_OFFERTIME; +#endif + return ntohl(ipaddr); + } + } + return 0; +} + +/**************************************************************************** + * Name: dhcpd_parseoptions + ****************************************************************************/ + +static inline bool dhcpd_parseoptions(void) +{ + uint32_t tmp; + uint8_t *ptr; + uint8_t overloaded; + uint8_t currfield; + int optlen = 0; + int remaining; + + /* Verify that the option field starts with a valid magic number */ + + ptr = g_state.ds_inpacket.options; + if (memcmp(ptr, g_magiccookie, 4) != 0) + { + /* Bad magic number... skip g_state.ds_outpacket */ + + ndbg("Bad magic: %d,%d,%d,%d\n", ptr[0], ptr[1], ptr[2], ptr[3]); + return false; + } + + /* Set up to parse the options */ + + ptr += 4; + remaining = DHCPD_OPTIONS_SIZE - 4; + overloaded = DHCPD_OPTION_FIELD; + currfield = DHCPD_OPTION_FIELD; + + /* Set all options to the default value */ + + g_state.ds_optmsgtype = 0; /* Incoming DHCP message type */ + g_state.ds_optreqip = 0; /* Requested IP address (host order) */ + g_state.ds_optserverip = 0; /* Serverip IP address (host order) */ + g_state.ds_optleasetime = 0; /* Requested lease time (host order) */ + g_state.ds_optend = NULL; + + do + { + /* The form of an option is: + * code - 1 byte + * length - 1 byte + * data - variable number of bytes + */ + + switch (ptr[DHCPD_OPTION_CODE]) + { + /* Skip over any padding bytes */ + + case DHCP_OPTION_PAD: + optlen = 1; + break; + + /* the Overload option is used to indicate that the DHCP 'sname' or 'file' + * fields are being overloaded by using them to carry DHCP options. A DHCP + * server inserts this option if the returned parameters will exceed the + * usual space allotted for options. + * + * If this option is present, the client interprets the specified additional + * fields after it concludes interpretation of the standard option fields. + * + * Legal values for this option are: + * + * 1 the 'file' field is used to hold options + * 2 the 'sname' field is used to hold options + * 3 both fields are used to hold options + */ + +#ifndef CONFIG_NET_DHCP_LIGHT + case DHCP_OPTION_OVERLOAD: + optlen = ptr[DHCPD_OPTION_LENGTH] + 2; + if (optlen >= 1 && optlen < remaining) + { + overloaded = ptr[DHCPD_OPTION_DATA]; + } + break; +#endif + + case DHCP_OPTION_END: +#ifndef CONFIG_NET_DHCP_LIGHT + if (currfield == DHCPD_OPTION_FIELD && + (overloaded & DHCPD_FILE_FIELD) != 0) + { + ptr = g_state.ds_inpacket.file; + remaining = sizeof(g_state.ds_inpacket.file); + currfield = DHCPD_FILE_FIELD; + } + else if (currfield == DHCPD_FILE_FIELD && + (overloaded & DHCPD_SNAME_FIELD) != 0) + { + ptr = g_state.ds_inpacket.sname; + remaining = sizeof(g_state.ds_inpacket.sname); + currfield = DHCPD_SNAME_FIELD; + } + else + { + return true; + } + break; +#else + return true; +#endif + + case DHCP_OPTION_REQ_IPADDR: /* Requested IP Address */ + optlen = ptr[DHCPD_OPTION_LENGTH] + 2; + if (optlen >= 4 && optlen < remaining) + { + memcpy(&tmp, &ptr[DHCPD_OPTION_DATA], 4); + g_state.ds_optreqip = (in_addr_t)ntohl(tmp); + } + break; + + case DHCP_OPTION_LEASE_TIME: /* IP address lease time */ + optlen = ptr[DHCPD_OPTION_LENGTH] + 2; + if (optlen >= 4 && optlen < remaining) + { + memcpy(&tmp, &ptr[DHCPD_OPTION_DATA], 4); + g_state.ds_optleasetime = (time_t)ntohl(tmp); + } + break; + + case DHCP_OPTION_MSG_TYPE: /* DHCP message type */ + optlen = ptr[DHCPD_OPTION_LENGTH] + 2; + if (optlen >= 1 && optlen < remaining) + { + g_state.ds_optmsgtype = ptr[DHCPD_OPTION_DATA]; + } + break; + + case DHCP_OPTION_SERVER_ID: /* Server identifier */ + optlen = ptr[DHCPD_OPTION_LENGTH] + 2; + if (optlen >= 4 && optlen < remaining) + { + memcpy(&tmp, &ptr[DHCPD_OPTION_DATA], 4); + g_state.ds_optserverip = (in_addr_t)ntohl(tmp); + } + break; + + default: + /* Skip over unsupported options */ + + optlen = ptr[DHCPD_OPTION_LENGTH] + 2; + break; + } + + /* Advance to the next option */ + + ptr += optlen; + remaining -= optlen; + } + while (remaining > 0); + return false; +} + +/**************************************************************************** + * Name: dhcpd_verifyreqip + ****************************************************************************/ + +static inline bool dhcpd_verifyreqip(void) +{ + struct lease_s *lease; + + /* Verify that the requested IP address is within the supported lease range */ + + if (g_state.ds_optreqip > 0 && + g_state.ds_optreqip >= CONFIG_NETUTILS_DHCPD_STARTIP && + g_state.ds_optreqip <= CONFIG_NETUTILS_DHCP_OPTION_ENDIP) + { + /* And verify that the lease has not already been taken or offered + * (unless the lease/offer is expired, then the address is free game). + */ + + lease = dhcpd_findbyipaddr(g_state.ds_optreqip); + if (!lease || dhcpd_leaseexpired(lease)) + { + return true; + } + } + return false; +} + +/**************************************************************************** + * Name: dhcpd_verifyreqleasetime + ****************************************************************************/ + +static inline bool dhcpd_verifyreqleasetime(uint32_t *leasetime) +{ + uint32_t tmp = g_state.ds_optleasetime; + + /* Did the client request a specific lease time? */ + + if (tmp != 0) + { + /* Yes.. Verify that the requested lease time is within a valid range */ + + if (tmp > CONFIG_NETUTILS_DHCPD_MAXLEASETIME) + { + tmp = CONFIG_NETUTILS_DHCPD_MAXLEASETIME; + } + else if (tmp < CONFIG_NETUTILS_DHCPD_MINLEASETIME) + { + tmp = CONFIG_NETUTILS_DHCPD_MINLEASETIME; + } + + /* Return the clipped lease time */ + + *leasetime = tmp; + return true; + } + return false; +} + +/**************************************************************************** + * Name: dhcpd_addoption + ****************************************************************************/ + +static int dhcpd_addoption(uint8_t *option) +{ + int offset; + int len = 4; + + if (g_state.ds_optend) + { + offset = g_state.ds_outpacket.options - g_state.ds_optend; + len = option[DHCPD_OPTION_LENGTH] + 2; + + /* Check if the option will fit into the options array */ + + if (offset + len + 1 < DHCPD_OPTIONS_SIZE) + { + /* Copy the option into the option array */ + + memcpy(g_state.ds_optend, option, len); + g_state.ds_optend += len; + *g_state.ds_optend = DHCP_OPTION_END; + } + } + return len; +} + +/**************************************************************************** + * Name: dhcpd_addoption8 + ****************************************************************************/ + +static int dhcpd_addoption8(uint8_t code, uint8_t value) +{ + uint8_t option[3]; + + /* Construct the option sequence */ + + option[DHCPD_OPTION_CODE] = code; + option[DHCPD_OPTION_LENGTH] = 1; + option[DHCPD_OPTION_DATA] = value; + + /* Add the option sequence to the response */ + + return dhcpd_addoption(option); +} + +/**************************************************************************** + * Name: dhcpd_addoption32 + ****************************************************************************/ + +static int dhcpd_addoption32(uint8_t code, uint32_t value) +{ + uint8_t option[6]; + + /* Construct the option sequence */ + + option[DHCPD_OPTION_CODE] = code; + option[DHCPD_OPTION_LENGTH] = 4; + memcpy(&option[DHCPD_OPTION_DATA], &value, 4); + + /* Add the option sequence to the response */ + + return dhcpd_addoption(option); +} + +/**************************************************************************** + * Name: dhcpd_soclet + ****************************************************************************/ + +static inline int dhcpd_socket(void) +{ + int sockfd; +#if defined(HAVE_SO_REUSEADDR) || defined(HAVE_SO_BROADCAST) + int optval; + int ret; +#endif + + /* Create a socket to listen for requests from DHCP clients */ + + sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + ndbg("socket failed: %d\n", errno); + return ERROR; + } + + /* Configure the socket */ + +#ifdef HAVE_SO_REUSEADDR + optval = 1; + ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)); + if (ret < 0) + { + ndbg("setsockopt SO_REUSEADDR failed: %d\n", errno); + close(sockfd); + return ERROR; + } +#endif + +#ifdef HAVE_SO_BROADCAST + optval = 1; + ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (void*)&optval, sizeof(int)); + if (ret < 0) + { + ndbg("setsockopt SO_BROADCAST failed: %d\n", errno); + close(sockfd); + return ERROR; + } +#endif + + return sockfd; + +} + +/**************************************************************************** + * Name: dhcpd_openresponder + ****************************************************************************/ + +static inline int dhcpd_openresponder(void) +{ + struct sockaddr_in addr; + int sockfd; + int ret; + + nvdbg("Responder: %08lx\n", ntohl(g_state.ds_serverip)); + + /* Create a socket to listen for requests from DHCP clients */ + + sockfd = dhcpd_socket(); + if (sockfd < 0) + { + ndbg("socket failed: %d\n", errno); + return ERROR; + } + + /* Bind the socket to a local port.*/ + + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = g_state.ds_serverip; + + ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + if (ret < 0) + { + ndbg("bind failed, port=%d addr=%08lx: %d\n", + addr.sin_port, (long)addr.sin_addr.s_addr, errno); + close(sockfd); + return ERROR; + } + + return sockfd; +} + +/**************************************************************************** + * Name: dhcpd_initpacket + ****************************************************************************/ + +static void dhcpd_initpacket(uint8_t mtype) +{ + uint32_t nulladdr = 0; + + /* Set up the generic parts of the DHCP server message */ + + memset(&g_state.ds_outpacket, 0, sizeof(struct dhcpmsg_s)); + + g_state.ds_outpacket.op = DHCP_REPLY; + g_state.ds_outpacket.htype = g_state.ds_inpacket.htype; + g_state.ds_outpacket.hlen = g_state.ds_inpacket.hlen; + + memcpy(&g_state.ds_outpacket.xid, &g_state.ds_inpacket.xid, 4); + memcpy(g_state.ds_outpacket.chaddr, g_state.ds_inpacket.chaddr, 16); + + if (memcmp(g_state.ds_outpacket.giaddr, &nulladdr, 4) != 0) + { + g_state.ds_outpacket.flags = g_state.ds_inpacket.flags; + } + else + { + g_state.ds_outpacket.flags = 0; + } + memset(g_state.ds_outpacket.giaddr, 0, 4); + + /* Add the generic options */ + + memcpy(g_state.ds_outpacket.options, g_magiccookie, 4); + g_state.ds_optend = &g_state.ds_outpacket.options[4]; + *g_state.ds_optend = DHCP_OPTION_END; + dhcpd_addoption8(DHCP_OPTION_MSG_TYPE, mtype); + dhcpd_addoption32(DHCP_OPTION_SERVER_ID, g_state.ds_serverip); +} + +/**************************************************************************** + * Name: dhcpd_sendpacket + ****************************************************************************/ + +static int dhcpd_sendpacket(int bbroadcast) +{ + struct sockaddr_in addr; + in_addr_t ipaddr; + int sockfd; + int len; + int ret = ERROR; + +#ifdef CONFIG_NETUTILS_DHCPD_IGNOREBROADCAST + /* This is a hack. I've had problems with Windows machines responding + * to unicast. I think this is associated with a Windows registry key in + * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DHCPServer\Parameters: + * The IgnoreBroadcastFlag value controls this behavior: A value of 1 will + * cause the server to ignore the client broadcast flag and always respond + * with multicast; the value 0 to allows clients to request unicast. + */ + + ipaddr = INADDR_BROADCAST; +#else + /* Determine which address to respond to (or if we need to broadcast the response) + * + * (1) If he caller know that it needs to multicast the response, it will set bbroadcast. + * (2) Otherwise, if the client already has and address (ciaddr), then use that for uni-cast + * (3) Broadcast if the client says it can't handle uni-cast (BOOTP_BROADCAST set) + * (4) Otherwise, the client claims it can handle the uni-casst response and we + * will uni-cast to the offered address (yiaddr). + * + * NOTE: We really should also check the giaddr field. If no zero, the server should + * send any return messages to the 'DHCP server' port on the BOOTP relay agent whose + * address appears in 'giaddr'. + */ + + if (bbroadcast) + { + ipaddr = INADDR_BROADCAST; + } + else if (memcmp(g_state.ds_outpacket.ciaddr, g_anyipaddr, 4) != 0) + { + dhcpd_arpupdate((uint16_t*)g_state.ds_outpacket.ciaddr, g_state.ds_outpacket.chaddr); + memcpy(&ipaddr, g_state.ds_outpacket.ciaddr, 4); + } + else if (g_state.ds_outpacket.flags & HTONS(BOOTP_BROADCAST)) + { + ipaddr = INADDR_BROADCAST; + } + else + { + dhcpd_arpupdate((uint16_t*)g_state.ds_outpacket.yiaddr, g_state.ds_outpacket.chaddr); + memcpy(&ipaddr, g_state.ds_outpacket.yiaddr, 4); + } +#endif + + /* Create a socket to respond with a packet to the client. We + * cannot re-use the listener socket because it is not bound correctly + */ + + sockfd = dhcpd_openresponder(); + if (sockfd >= 0) + { + /* Then send the reponse to the DHCP client port at that address */ + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = HTONS(DHCP_CLIENT_PORT); + addr.sin_addr.s_addr = ipaddr; + + /* Send the minimum sized packet that includes the END option */ + + len = (g_state.ds_optend - (uint8_t*)&g_state.ds_outpacket) + 1; + nvdbg("sendto %08lx:%04x len=%d\n", + (long)ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port), len); + + ret = sendto(sockfd, &g_state.ds_outpacket, len, 0, + (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + close(sockfd); + } + + return ret; +} + +/**************************************************************************** + * Name: dhcpd_sendoffer + ****************************************************************************/ + +static inline int dhcpd_sendoffer(in_addr_t ipaddr, uint32_t leasetime) +{ + in_addr_t netaddr; + + /* IP address is in host order */ + + nvdbg("Sending offer: %08lx\n", (long)ipaddr); + + /* Initialize the outgoing packet */ + + dhcpd_initpacket(DHCPOFFER); + + /* Add the address offered to the client (converting to network order) */ + + netaddr = htonl(ipaddr); + memcpy(g_state.ds_outpacket.yiaddr, &netaddr, 4); + + /* Add the leasetime to the response options */ + + dhcpd_addoption32(DHCP_OPTION_LEASE_TIME, htonl(leasetime)); + + /* Send the offer response */ + +#ifdef CONFIG_NETUTILS_DHCPD_IGNOREBROADCAST + return dhcpd_sendpacket(true); +#else + return dhcpd_sendpacket(false); +#endif +} + +/**************************************************************************** + * Name: dhcpd_sendnak + ****************************************************************************/ + +static int dhcpd_sendnak(void) +{ + /* Initialize and send the NAK response */ + + dhcpd_initpacket(DHCPNAK); + memcpy(g_state.ds_outpacket.ciaddr, g_state.ds_inpacket.ciaddr, 4); + return dhcpd_sendpacket(true); +} + +/**************************************************************************** + * Name: dhcpd_sendack + ****************************************************************************/ + +int dhcpd_sendack(in_addr_t ipaddr) +{ + uint32_t leasetime = CONFIG_NETUTILS_DHCPD_LEASETIME; + in_addr_t netaddr; + + /* Initialize the ACK response */ + + dhcpd_initpacket(DHCPACK); + memcpy(g_state.ds_outpacket.ciaddr, g_state.ds_inpacket.ciaddr, 4); + + /* Add the IP address assigned to the client */ + + netaddr = htonl(ipaddr); + memcpy(g_state.ds_outpacket.yiaddr, &netaddr, 4); + + /* Did the client request a specific lease time? */ + + (void)dhcpd_verifyreqleasetime(&leasetime); + + /* Add the lease time to the response */ + + dhcpd_addoption32(DHCP_OPTION_LEASE_TIME, htonl(leasetime)); + +#ifdef CONFIG_NETUTILS_DHCPD_IGNOREBROADCAST + if (dhcpd_sendpacket(true) < 0) +#else + if (dhcpd_sendpacket(false) < 0) +#endif + { + return ERROR; + } + + dhcpd_setlease(g_state.ds_inpacket.chaddr, ipaddr, leasetime); + return OK; +} + +/**************************************************************************** + * Name: dhcpd_discover + ****************************************************************************/ + +static inline int dhcpd_discover(void) +{ + struct lease_s *lease; + in_addr_t ipaddr; + uint32_t leasetime = CONFIG_NETUTILS_DHCPD_LEASETIME; + + /* Check if the client is aleady in the lease table */ + + lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr); + if (lease) + { + /* Yes... get the remaining time on the lease */ + +#ifdef HAVE_LEASE_TIME + if (!dhcpd_leaseexpired(lease)) + { + leasetime = lease->expiry - dhcpd_time(); + if (leasetime < CONFIG_NETUTILS_DHCPD_MINLEASETIME) + { + leasetime = CONFIG_NETUTILS_DHCPD_MINLEASETIME; + } + } +#endif + /* Get the IP address associated with the lease (host order) */ + + ipaddr = dhcp_leaseipaddr(lease); + nvdbg("Already have lease for IP %08lx\n", (long)ipaddr); + } + + /* Check if the client has requested a specific IP address */ + + else if (dhcpd_verifyreqip()) + { + /* Use the requested IP address (host order) */ + + ipaddr = g_state.ds_optreqip; + nvdbg("User requested IP %08lx\n", (long)ipaddr); + } + else + { + /* No... allocate a new IP address (host order)*/ + + ipaddr = dhcpd_allocipaddr(); + nvdbg("Allocated IP %08lx\n", (long)ipaddr); + } + + /* Did we get any IP address? */ + + if (!ipaddr) + { + /* Nope... return failure */ + + ndbg("Failed to get IP address\n"); + return ERROR; + } + + /* Reserve the leased IP for a shorter time for the offer */ + + if (!dhcpd_setlease(g_state.ds_inpacket.chaddr, ipaddr, CONFIG_NETUTILS_DHCPD_OFFERTIME)) + { + ndbg("Failed to set lease\n"); + return ERROR; + } + + /* Check if the client has requested a specific lease time */ + + (void)dhcpd_verifyreqleasetime(&leasetime); + + /* Send the offer response */ + + return dhcpd_sendoffer(ipaddr, leasetime); +} + +/**************************************************************************** + * Name: dhcpd_request + ****************************************************************************/ + +static inline int dhcpd_request(void) +{ + struct lease_s *lease; + in_addr_t ipaddr = 0; + uint8_t response = 0; + + /* Check if this client already holds a lease. This can happen when the client (1) + * the IP is reserved for the client from a previous offer, or (2) the client is + * re-initializing or rebooting while the lease is still valid. + */ + + lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr); + if (lease) + { + /* Yes.. the client already holds a lease. Verify that the request is consistent + * with the existing lease (host order). + */ + + ipaddr = dhcp_leaseipaddr(lease); + nvdbg("Lease ipaddr: %08x Server IP: %08x Requested IP: %08x\n", + ipaddr, g_state.ds_optserverip, g_state.ds_optreqip); + + if (g_state.ds_optserverip) + { + /* ACK if the serverip is correct and the requested IP address is the one + * already offered to the client. + */ + + if (g_state.ds_optserverip == ntohl(g_state.ds_serverip) && + (g_state.ds_optreqip != 0 || g_state.ds_optreqip == ipaddr)) + { + response = DHCPACK; + } + else + { + response = DHCPNAK; + } + } + + /* We have the lease and no server IP was requested. Was a specific IP address + * requested? (host order) + */ + + else if (g_state.ds_optreqip) + { + /* Yes..ACK if the requested IP address is the one already leased. + * Both addresses are in host order. + */ + + if (ipaddr == g_state.ds_optreqip) + { + response = DHCPACK; + } + else + { + response = DHCPNAK; + } + } + + /* The client has specified neither a server IP nor requested IP address */ + + else + { + /* ACK if the IP used by the client is the one already assigned to it. + * NOTE ipaddr is in host order; ciaddr is network order! + */ + + uint32_t tmp = htonl(ipaddr); + if (memcmp(&tmp, g_state.ds_inpacket.ciaddr, 4) == 0) + { + response = DHCPACK; + } + else + { + response = DHCPNAK; + } + } + } + + /* The client does not hold a lease (referenced by its MAC address) and is + * requesting a specific IP address that was, apparently, never offered to + * to the client. Perform some sanity checks before sending the NAK. + */ + + else if (g_state.ds_optreqip && !g_state.ds_optserverip) + { + nvdbg("Server IP: %08x Requested IP: %08x\n", + g_state.ds_optserverip, g_state.ds_optreqip); + + /* Is this IP address already assigned? */ + + lease = dhcpd_findbyipaddr(g_state.ds_optreqip); + if (lease) + { + /* Yes.. Send NAK unless the lease has expired */ + + if (!dhcpd_leaseexpired(lease)) + { + response = DHCPNAK; + } + } + + /* No.. is the requested IP address in range? NAK if not */ + + else if (g_state.ds_optreqip < CONFIG_NETUTILS_DHCPD_STARTIP || + g_state.ds_optreqip > CONFIG_NETUTILS_DHCP_OPTION_ENDIP) + { + response = DHCPNAK; + } + } + + /* Otherwise, the client does not hold a lease and is not requesting any + * specific IP address. + */ + + /* Finally, either (1) send the ACK, (2) send a NAK, or (3) remain silent + * based on the checks above. + */ + + if (response == DHCPACK) + { + nvdbg("ACK IP %08lx\n", (long)ipaddr); + dhcpd_sendack(ipaddr); + } + else if (response == DHCPNAK) + { + nvdbg("NAK IP %08lx\n", (long)ipaddr); + dhcpd_sendnak(); + } + else + { + nvdbg("Remaining silent IP %08lx\n", (long)ipaddr); + } + + return OK; +} + +/**************************************************************************** + * Name: dhcpd_decline + ****************************************************************************/ + +static inline int dhcpd_decline(void) +{ + struct lease_s *lease; + + /* Find the lease associated with this hardware address */ + + lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr); + if (lease) + { + /* Disassociate the IP from the MAC, but prevent re-used of this + * address for a period of time. + */ + + memset(lease->mac, 0, DHCP_HLEN_ETHERNET); +#ifdef HAVE_LEASE_TIME + lease->expiry = dhcpd_time() + CONFIG_NETUTILS_DHCPD_DECLINETIME; +#endif + } + return OK; +} + +static inline int dhcpd_release(void) +{ + struct lease_s *lease; + + /* Find the lease associated with this hardware address */ + + lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr); + if (lease) + { + /* Release the IP address now */ + + memset(lease, 0, sizeof(struct lease_s)); + } + return OK; +} + +/**************************************************************************** + * Name: dhcpd_openlistener + ****************************************************************************/ + +static inline int dhcpd_openlistener(void) +{ + struct sockaddr_in addr; + struct ifreq req; + int sockfd; + int ret; + + /* Create a socket to listen for requests from DHCP clients */ + + sockfd = dhcpd_socket(); + if (sockfd < 0) + { + ndbg("socket failed: %d\n", errno); + return ERROR; + } + + /* Get the IP address of the selected device */ + + strncpy(req.ifr_name, CONFIG_NETUTILS_DHCPD_INTERFACE, IFNAMSIZ); + ret = ioctl(sockfd, SIOCGIFADDR, (unsigned long)&req); + if (ret < 0) + { + ndbg("setsockopt SIOCGIFADDR failed: %d\n", errno); + close(sockfd); + return ERROR; + } + g_state.ds_serverip = ((struct sockaddr_in*)&req.ifr_addr)->sin_addr.s_addr; + nvdbg("serverip: %08lx\n", ntohl(g_state.ds_serverip)); + + /* Bind the socket to a local port. We have to bind to INADDRY_ANY to + * receive broadcast messages. + */ + + addr.sin_family = AF_INET; + addr.sin_port = htons(DHCP_SERVER_PORT); + addr.sin_addr.s_addr = INADDR_ANY; + + ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + if (ret < 0) + { + ndbg("bind failed, port=%d addr=%08lx: %d\n", + addr.sin_port, (long)addr.sin_addr.s_addr, errno); + close(sockfd); + return ERROR; + } + + return sockfd; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dhcpd_run + ****************************************************************************/ + +int dhcpd_run(void) +{ + int sockfd; + int nbytes; + + nvdbg("Started\n"); + + /* Initialize everything to zero */ + + memset(&g_state, 0, sizeof(struct dhcpd_state_s)); + + /* Now loop indefinitely, reading packets from the DHCP server socket */ + + sockfd = -1; + for (;;) + { + /* Create a socket to listen for requests from DHCP clients */ + + if (sockfd < 0) + { + sockfd = dhcpd_openlistener(); + if (sockfd < 0) + { + ndbg("Failed to create socket\n"); + break; + } + } + + /* Read the next g_state.ds_outpacket */ + + nbytes = recv(sockfd, &g_state.ds_inpacket, sizeof(struct dhcpmsg_s), 0); + if (nbytes < 0) + { + /* On errors (other EINTR), close the socket and try again */ + + ndbg("recv failed: %d\n", errno); + if (errno != EINTR) + { + close(sockfd); + sockfd = -1; + } + continue; + } + + /* Parse the incoming message options */ + + if (!dhcpd_parseoptions()) + { + /* Failed to parse the message options */ + + ndbg("No msg type\n"); + continue; + } + +#ifdef CONFIG_NETUTILS_DHCPD_HOST + /* Get the poor little uC a change to get its recvfrom in place */ + + usleep(500*1000); +#endif + + /* Now process the incoming DHCP message by its message type */ + + switch (g_state.ds_optmsgtype) + { + case DHCPDISCOVER: + nvdbg("DHCPDISCOVER\n"); + dhcpd_discover(); + break; + + case DHCPREQUEST: + nvdbg("DHCPREQUEST\n"); + dhcpd_request(); + break; + + case DHCPDECLINE: + nvdbg("DHCPDECLINE\n"); + dhcpd_decline(); + break; + + case DHCPRELEASE: + nvdbg("DHCPRELEASE\n"); + dhcpd_release(); + break; + + case DHCPINFORM: /* Not supported */ + default: + ndbg("Unsupported message type: %d\n", g_state.ds_optmsgtype); + break; + } + } + return OK; +} diff --git a/apps/netutils/ftpc/Makefile b/apps/netutils/ftpc/Makefile new file mode 100644 index 000000000..59121e3b7 --- /dev/null +++ b/apps/netutils/ftpc/Makefile @@ -0,0 +1,113 @@ +############################################################################ +# apps/netutils/ftpc/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# DHCP Daemn Library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_TCP),y) +# FTP connection management +CSRCS = ftpc_connect.c ftpc_disconnect.c + +# FTP commands +CSRCS += ftpc_cdup.c ftpc_chdir.c ftpc_chmod.c ftpc_filesize.c ftpc_filetime.c +CSRCS += ftpc_help.c ftpc_idle.c ftpc_listdir.c ftpc_login.c ftpc_mkdir.c +CSRCS += ftpc_noop.c ftpc_rpwd.c ftpc_quit.c ftpc_rename.c ftpc_rmdir.c ftpc_unlink.c +CSRCS += ftpc_cmd.c + +# FTP transfers +CSRCS += ftpc_getfile.c ftpc_putfile.c ftpc_transfer.c + +# FTP responses +CSRCS += ftpc_response.c ftpc_getreply.c + +# FTP helpers +CSRCS += ftpc_utils.c ftpc_socket.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/ftpc/README.txt b/apps/netutils/ftpc/README.txt new file mode 100644 index 000000000..d995227c7 --- /dev/null +++ b/apps/netutils/ftpc/README.txt @@ -0,0 +1,81 @@ +/* FTP Commands *************************************************************/ +/* Command summary: + * + * ABOR - abort a file transfer + * ACCT - send account information + * APPE - append to a remote file + * CDUP - CWD to the parent of the current directory + * CWD - change working directory + * DELE - delete a remote file + * HELP - return help on using the server + * LIST - list remote files + * MDTM - return the modification time of a file + * MKD - make a remote directory + * MLSD - Standardized directory listing (instead of LIST) + * MLST - Standardized object listing (instead of LIST) + * MODE - set transfer mode + * NLST - name list of remote directory + * NOOP - do nothing + * PASS - send password + * PASV - enter passive mode + * PORT - open a data port + * PWD - print working directory + * QUIT - terminate the connection + * REIN - reinitialize the connection + * RETR - retrieve a remote file + * REST - Sets the point at which a file transfer should start + * RMD - remove a remote directory + * RNFR - rename from + * RNTO - rename to + * SITE - site-specific commands + * SIZE - return the size of a file + * STOR - store a file on the remote host + * STOU - store a file uniquely + * STRU - set file transfer structure + * STAT - return server status + * SYST - return system type + * TYPE - set transfer type + * USER - send username + * +/* FTP Replies **************************************************************/ + * + * 110 - Restart marker reply. + * 120 - Service ready in nnn minutes. + * 125 - Data connection already open; transfer starting. + * 150 - File status okay; about to open data connection. + * 200 - Command okay. + * 202 - Command not implemented, superfluous at this site. + * 211 - System status, or system help reply. + * 212 - Directory status. + * 213 - File status. + * 214 - Help message. + * 215 - NAME system type. + * 220 - Service ready for new user. + * 221 - Service closing control connection. + * 225 - Data connection open; no transfer in progress. + * 226 - Closing data connection. + * 227 - Entering Passive Mode (h1,h2,h3,h4,p1,p2). + * 230 - User logged in, proceed. + * 250 - Requested file action okay, completed. + * 257 - "PATHNAME" created. + * 331 - User name okay, need password. + * 332 - Need account for login. + * 350 - Requested file action pending further information. + * 421 - Service not available, closing control connection. + * 425 - Can't open data connection. + * 426 - Connection closed; transfer aborted. + * 450 - Requested file action not taken. + * 451 - Requested action aborted: local error in processing. + * 452 - Requested action not taken. + * 500 - Syntax error, command unrecognized. + * 501 - Syntax error in parameters or arguments. + * 502 - Command not implemented. + * 503 - Bad sequence of commands. + * 504 - Command not implemented for that parameter. + * 530 - Not logged in. + * 532 - Need account for storing files. + * 550 - Requested action not taken. + * 551 - Requested action aborted: page type unknown. + * 552 - Requested file action aborted. + * 553 - Requested action not taken. + */ diff --git a/apps/netutils/ftpc/ftpc_cdup.c b/apps/netutils/ftpc/ftpc_cdup.c new file mode 100644 index 000000000..2b4aa0973 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_cdup.c @@ -0,0 +1,87 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_cdup.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_cdup + * + * Description: + * Make the parent of the current directory be the new current directory. + * + ****************************************************************************/ + +int ftpc_cdup(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + ret = ftpc_cmd(session, "CDUP"); + session->currdir = ftpc_rpwd(handle); + return ret; +} + diff --git a/apps/netutils/ftpc/ftpc_chdir.c b/apps/netutils/ftpc/ftpc_chdir.c new file mode 100644 index 000000000..9b512a1f3 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_chdir.c @@ -0,0 +1,91 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_chdir.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_chdir + * + * Description: + * Change the current working directory. + * + ****************************************************************************/ + +int ftpc_chdir(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + ret = ftpc_cmd(session, "CWD %s", path); + if (ret != OK) + { + return ret; + } + + session->currdir = ftpc_rpwd(handle); + return OK; +} diff --git a/apps/netutils/ftpc/ftpc_chmod.c b/apps/netutils/ftpc/ftpc_chmod.c new file mode 100644 index 000000000..13d06f403 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_chmod.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_chmod.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <debug.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_chmod + * + * Description: + * Change the protections on the remote file. + * + ****************************************************************************/ + +int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + /* Does the server support the size CHMOD command? */ + + if (FTPC_HAS_CHMOD(session)) + { + ret = ftpc_cmd(session, "SITE CHMOD %s %s", path, mode); + + /* Check for "502 Command not implemented" */ + + if (session->code == 502) + { + /* No.. the server does not support the SITE CHMOD command */ + + FTPC_CLR_CHMOD(session); + } + + return OK; + } + else + { + ndbg("Server does not support SITE CHMOD\n"); + } + + return ERROR; +} diff --git a/apps/netutils/ftpc/ftpc_cmd.c b/apps/netutils/ftpc/ftpc_cmd.c new file mode 100644 index 000000000..dc031790d --- /dev/null +++ b/apps/netutils/ftpc/ftpc_cmd.c @@ -0,0 +1,238 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_cmd.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <errno.h> +#include <debug.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_restore + * + * Description: + * Restore the connection to the server and log in again. + * + ****************************************************************************/ + +#ifdef CONFIG_FTP_AUTORECONNECT +static int ftpc_restore(struct ftpc_session_s *session) +{ + int ret; + + if (session) + { + /* Set the initial directory to the last valid current directory */ + + free(session->initrdir); + session->initrdir = ftpc_dequote(session->currdir); + + /* Reconnect to the server */ + + ret = ftpc_reconnect(session); + if (ret == 0) + { + /* Log into the server */ + + ret = ftpc_relogin(session); + } + else + { + /* Failed to reconnect to the server */ + + ftpc_reset(session); + } + return ret; + } + + return ERROR; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_cmd + * + * Description: + * Send the specified command to the server. + * + ****************************************************************************/ + +int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...) +{ + va_list ap; +#ifdef CONFIG_FTP_AUTORECONNECT + bool reconnect = false; +#endif + int ret; + + /* Verify that we are still connecte to the server */ + + if (!ftpc_sockconnected(&session->cmd)) + { + ndbg("Cmd channel si not connected\n"); + goto errout; + } + + /* Loop, reconnecting as necessary until the command is sent */ + +#ifdef CONFIG_FTP_AUTORECONNECT + for (;;) +#endif + { + /* Send the command */ + + va_start(ap, cmd); + ret = ftpc_sockvprintf(&session->cmd, cmd, ap); + if (ret >= 0) + { + ret = ftpc_sockprintf(&session->cmd, "\r\n"); + if (ret >= 0) + { + ret = ftpc_sockflush(&session->cmd); + } + } + va_end(ap); + + /* Check for an error in sending the data */ + + if (ret < 0) + { + ndbg("Error sending cmd %s: %d\n", cmd, errno); + goto errout; + } + + /* Get the response to the command */ + + ret = fptc_getreply(session); + if (ret < 0) + { + ndbg("Error getting reply: %d\n", errno); + goto errout; + } + + /* Check for "421 Service not available, closing control connection" */ + + if (session->code == 421) + { + /* Server is closing the control connection. */ + + ndbg("Server closed control connection\n"); + + /* If we were previously logged in and this is not a QUIT commnad + * then attempt to automatically reconnect to the server. + */ + +#ifdef CONFIG_FTP_AUTORECONNECT + if (ftpc_loggedin(session) && strcasecmp(cmd, "QUIT") != 0) + { + /* Don't try re-connecting more than once */ + + if (reconnect) + { + ndbg("Reconnect failed\n"); + goto errout; + } + else + { + /* Try to restore the connection and, if successful, + * continue the loop and try to send the command again. + */ + + ndbg("Reconnecting...\n"); + reconnect = true; + ret = ftpc_restore(); + if (ret < 0) + { + ndbg("Failed to restore the connection"); + goto errout; + } + continue; + } + } + else +#endif + { + /* Don't try to connect, just return an error (retaining + * the session response code (421) + */ + + return ERROR; + } + } + + /* The command was successfully sent */ + + return OK; + } + +errout: + session->code = -1; + return ERROR; +} diff --git a/apps/netutils/ftpc/ftpc_config.h b/apps/netutils/ftpc/ftpc_config.h new file mode 100644 index 000000000..9dc90085c --- /dev/null +++ b/apps/netutils/ftpc/ftpc_config.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_config.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_FTPC_FTPC_CONFIG_H +#define __APPS_NETUTILS_FTPC_FTPC_CONFIG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* This is a mindless little wrapper around include/nuttx/config.h. Every + * file in the ftpc directory includes this file at the very beginning of + * of the file (instead of include/nuttx/config.h). The only purpose of + * this file is to muck with some of the settings to support some debug + * features. + * + * The FPT client uses common networking debug macros (ndbg and nvdbg). + * This can be overwhelming if there is a lot of networking debug output + * as well. But by defining CONFIG_DEBUG_FTPC, this file will force + * networking debug ON only for the files within this directory. + */ + +#if !defined(CONFIG_DEBUG_NET) && defined(CONFIG_DEBUG_FTPC) +# define CONFIG_DEBUG_NET 1 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* __APPS_NETUTILS_FTPC_FTPC_CONFIG_H */ diff --git a/apps/netutils/ftpc/ftpc_connect.c b/apps/netutils/ftpc/ftpc_connect.c new file mode 100644 index 000000000..f36fa08e1 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_connect.c @@ -0,0 +1,250 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_connect.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_connect + * + * Description: + * Create a session handle and connect to the server. + * + ****************************************************************************/ + +SESSION ftpc_connect(FAR struct ftpc_connect_s *server) +{ + FAR struct ftpc_session_s *session; + int ret; + + /* Allocate a session structure */ + + session = (struct ftpc_session_s *)zalloc(sizeof(struct ftpc_session_s)); + if (!session) + { + ndbg("Failed to allocate a session\n"); + set_errno(ENOMEM); + goto errout; + } + + /* Initialize the session structure with all non-zero and variable values */ + + session->addr.s_addr = server->addr.s_addr; + session->flags &= ~FTPC_FLAGS_CLEAR; + session->flags |= FTPC_FLAGS_SET; + session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; + session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; + session->pid = getpid(); + + /* Use the default port if the user specified port number zero */ + + if (!server->port) + { + session->port = HTONS(CONFIG_FTP_DEFPORT); + } + else + { + session->port = htons(server->port); + } + + /* Get the local home directory, i.e., the value of the PWD environment + * variable at the time of the connection. We keep a local copy so that + * we can change the current working directory without effecting any other + * logic that may be in same context. + */ + + session->homeldir = strdup(ftpc_lpwd()); +/* session->curldir = strdup(sssion->homeldir); */ + + /* Create up a timer to prevent hangs */ + + session->wdog = wd_create(); + + /* And (Re-)connect to the server */ + + ret = ftpc_reconnect(session); + if (ret != OK) + { + ndbg("ftpc_reconnect() failed: %d\n", errno); + goto errout_with_alloc; + } + + return (SESSION)session; + +errout_with_alloc: + free(session); +errout: + return NULL; +} + +/**************************************************************************** + * Name: ftpc_reconnect + * + * Description: + * re-connect to the server either initially, or after loss of connection. + * + ****************************************************************************/ + +int ftpc_reconnect(FAR struct ftpc_session_s *session) +{ + struct sockaddr_in addr; +#ifdef CONFIG_DEBUG + char *tmp; +#endif + int ret; + + /* Re-initialize the session structure */ + + session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; + session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; + session->xfrmode = FTPC_XFRMODE_UNKNOWN; + + /* Set up a timer to prevent hangs */ + + ret = wd_start(session->wdog, session->conntimeo, ftpc_timeout, 1, session); + if (ret != OK) + { + ndbg("wd_start() failed\n"); + goto errout; + } + + /* Initialize a socket */ + + ret = ftpc_sockinit(&session->cmd); + if (ret != OK) + { + ndbg("ftpc_sockinit() failed: %d\n", errno); + goto errout; + } + + /* Connect the socket to the server */ + +#ifdef CONFIG_DEBUG + tmp = inet_ntoa(session->addr); + ndbg("Connecting to server address %s:%d\n", tmp, ntohs(session->port)); +#endif + + addr.sin_family = AF_INET; + addr.sin_port = session->port; + addr.sin_addr.s_addr = session->addr.s_addr; + + ret = ftpc_sockconnect(&session->cmd, &addr); + if (ret != OK) + { + ndbg("ftpc_sockconnect() failed: %d\n", errno); + goto errout_with_socket; + } + + /* Read startup message from server */ + + fptc_getreply(session); + + /* Check for "120 Service ready in nnn minutes" */ + + if (session->code == 120) + { + fptc_getreply(session); + } + wd_cancel(session->wdog); + + if (!ftpc_sockconnected(&session->cmd)) + { + ftpc_reset(session); + goto errout; + } + + /* Check for "220 Service ready for new user" */ + + if (session->code == 220) + { + FTPC_SET_CONNECTED(session); + } + + if (!FTPC_IS_CONNECTED(session)) + { + goto errout_with_socket; + } + +#ifdef CONFIG_DEBUG + ndbg("Connected\n"); + tmp = inet_ntoa(addr.sin_addr); + ndbg(" Remote address: %s:%d\n", tmp, ntohs(addr.sin_port)); + tmp = inet_ntoa(session->cmd.laddr.sin_addr); + ndbg(" Local address: %s:%d\n", tmp, ntohs(session->cmd.laddr.sin_port)); +#endif + return OK; + +errout_with_socket: + ftpc_sockclose(&session->cmd); +errout: + return ERROR; +} diff --git a/apps/netutils/ftpc/ftpc_disconnect.c b/apps/netutils/ftpc/ftpc_disconnect.c new file mode 100644 index 000000000..b2855ea37 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_disconnect.c @@ -0,0 +1,102 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_disconnect.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdlib.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_disconnect + * + * Description: + * Disconnect from the server and destroy the session handle.. + * + ****************************************************************************/ + +void ftpc_disconnect(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + if (session) + { + /* Release sockets */ + + ftpc_sockclose(&session->data); + ftpc_sockclose(&session->cmd); + + /* Free strings */ + + free(session->uname); + free(session->pwd); + free(session->initrdir); + free(session->homerdir); + free(session->currdir); + + /* Then destroy the session */ + + free(session); + } +} diff --git a/apps/netutils/ftpc/ftpc_filesize.c b/apps/netutils/ftpc/ftpc_filesize.c new file mode 100644 index 000000000..d827f736e --- /dev/null +++ b/apps/netutils/ftpc/ftpc_filesize.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_filesize.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdint.h> +#include <stdio.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_filesize + * + * Description: + * Return the size of the given file on the remote server. + * + ****************************************************************************/ + +off_t ftpc_filesize(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + unsigned long ret; + + /* Check if the host supports the SIZE command */ + + if (!FTPC_HAS_SIZE(session)) + { + return ERROR; + } + + if (ftpc_xfrmode(session, FTPC_XFRMODE_ASCII) != 0) + { + return ERROR; + } + + ret = ftpc_cmd(session, "SIZE %s", path); + + /* Check for "502 Command not implemented" */ + + if (session->code == 502) + { + /* No.. the host does not support the SIZE command */ + + FTPC_CLR_SIZE(session); + return ERROR; + } + + sscanf(session->reply, "%*s %lu", &ret); + return (off_t)ret; +} diff --git a/apps/netutils/ftpc/ftpc_filetime.c b/apps/netutils/ftpc/ftpc_filetime.c new file mode 100644 index 000000000..6b3a1d6db --- /dev/null +++ b/apps/netutils/ftpc/ftpc_filetime.c @@ -0,0 +1,134 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_filetime.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <string.h> +#include <time.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_filetime + * + * Descripton: + * Return the timestamp on the remote file. Returned time is UTC + * (Universal Coordinated Time). + * + ****************************************************************************/ + +time_t ftpc_filetime(SESSION handle, FAR const char *filename) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + struct tm timestamp; + int ret; + + /* Make sure that the server is still connected */ + + if (!ftpc_connected(session)) + { + return ERROR; + } + + /* Does the server support the MDTM command? */ + + if (!FTPC_HAS_MDTM(session)) + { + return ERROR; + } + + /* Get the file time in UTC */ + + memset(×tamp, 0, sizeof(timestamp)); + ret = ftpc_cmd(session, "MDTM %s", filename); + if (ret != OK) + { + return ERROR; + } + + /* Check for "202 Command not implemented, superfluous at this site" */ + + if (session->code == 202) + { + FTPC_CLR_MDTM(session); + return ERROR; + } + + /* Check for "213 File status" */ + + if (session->code != 213) + { + return ERROR; + } + + /* Time is Universal Coordinated Time */ + + sscanf(session->reply, "%*s %04d%02d%02d%02d%02d%02d", + ×tamp.tm_year, ×tamp.tm_mon, ×tamp.tm_mday, + ×tamp.tm_hour, ×tamp.tm_min, ×tamp.tm_sec); + timestamp.tm_year -= 1900; + timestamp.tm_mon--; + return mktime(×tamp); +} diff --git a/apps/netutils/ftpc/ftpc_getfile.c b/apps/netutils/ftpc/ftpc_getfile.c new file mode 100644 index 000000000..06532c22c --- /dev/null +++ b/apps/netutils/ftpc/ftpc_getfile.c @@ -0,0 +1,429 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_getfile.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <debug.h> +#include <errno.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_recvinit + * + * Description: + * Initialize to receive a file + * + ****************************************************************************/ + +static int ftpc_recvinit(struct ftpc_session_s *session, FAR const char *path, + uint8_t xfrmode, off_t offset) +{ + int ret; + + /* Reset transfer related variables */ + + ftpc_xfrreset(session); + + ret = ftpc_xfrinit(session); + if (ret != OK) + { + return ERROR; + } + + /* Configure the transfer: Initial file offset and tranfer mode */ + + session->offset = 0; + ftpc_xfrmode(session, xfrmode); + + /* Handle the resume offset (caller is responsible for fseeking in the + * file) + */ + + if (offset > 0) + { + /* Send the REST command. This command sets the offset where the + * transfer should start. This must come after PORT or PASV commands. + */ + + ret = ftpc_cmd(session, "REST %ld", offset); + if (ret < 0) + { + ndbg("REST command failed: %d\n", errno); + return ERROR; + } + + session->size = offset; + } + + /* Send the RETR (Retrieve a remote file) command. Normally the server + * responds with a mark using code 150: + * + * - "150 File status okay; about to open data connection" + * + * It then stops accepting new connections, attempts to send the contents + * of the file over the data connection, and closes the data connection. + * Finally it either accepts the RETR request with: + * + * - "226 Closing data connection" if the entire file was successfully + * written to the server's TCP buffers + * + * Or rejects the RETR request with: + * + * - "425 Can't open data connection" if no TCP connection was established + * - "426 Connection closed; transfer aborted" if the TCP connection was + * established but then broken by the client or by network failure + * - "451 Requested action aborted: local error in processing" or + * "551 Requested action aborted: page type unknown" if the server had + * trouble reading the file from disk. + */ + + ret = ftpc_cmd(session, "RETR %s", path); + if (ret < 0) + { + ndbg("RETR command failed: %d\n", errno); + return ERROR; + } + + /* In active mode, we need to accept a connection on the data socket + * (in passive mode, we have already connected the data channel to + * the FTP server). + */ + + if (!FTPC_IS_PASSIVE(session)) + { + ret = ftpc_sockaccept(&session->data); + if (ret != OK) + { + ndbg("Data connection not accepted\n"); + } + } + + return ret; +} + +/**************************************************************************** + * Name: ftpc_recvbinary + * + * Description: + * Receive a binary file. + * + ****************************************************************************/ + +static int ftpc_recvbinary(FAR struct ftpc_session_s *session, + FAR FILE *rinstream, FAR FILE *loutstream) +{ + ssize_t nread; + ssize_t nwritten; + + /* Loop until the entire file is received */ + + for (;;) + { + /* Read the data from the socket */ + + nread = fread(session->buffer, sizeof(char), CONFIG_FTP_BUFSIZE, rinstream); + if (nread <= 0) + { + /* nread < 0 is an error */ + + if (nread < 0) + { + /* errno should already be set by fread */ + + (void)ftpc_xfrabort(session, rinstream); + return ERROR; + } + + /* nread == 0 means end of file. Return success */ + + return OK; + } + + /* Write the data to the file */ + + nwritten = fwrite(session->buffer, sizeof(char), nread, loutstream); + if (nwritten != nread) + { + (void)ftpc_xfrabort(session, loutstream); + + /* If nwritten < 0 errno should already be set by fwrite. + * What would a short write mean? + */ + + return ERROR; + } + + /* Increment the size of the file written */ + + session->size += nwritten; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_getfile + * + * Description: + * Get a file from the remote host. + * + ****************************************************************************/ + +int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname, + uint8_t how, uint8_t xfrmode) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + struct stat statbuf; + FILE *loutstream; + FAR char *abslpath; + off_t offset; + int ret; + + /* Don't call this with a NULL remote file name */ + + DEBUGASSERT(rname); + + /* If the local name is not specified, then it is assumed to the same as + * the remote file name. + */ + + if (!lname) + { + lname = rname; + } + + /* Get the full path to the local file */ + + abslpath = ftpc_abslpath(session, lname); + if (!abslpath) + { + ndbg("ftpc_abslpath(%s) failed: %d\n", errno); + goto errout; + } + + /* Get information about the local file */ + + ret = stat(abslpath, &statbuf); + if (ret == 0) + { + /* It already exists. Is it a directory? */ + + if (S_ISDIR(statbuf.st_mode)) + { + ndbg("'%s' is a directory\n", abslpath); + goto errout_with_abspath; + } + } + + /* Is it write-able? */ + +#ifdef S_IWRITE + if (!(statbuf.st_mode & S_IWRITE)) + { + ndbg("'%s' permission denied\n", abslpath); + goto errout_with_abspath; + } +#endif + + /* Are we resuming the transfers? Is so then the starting offset is the + * size of the existing, partial file. + */ + + if (how == FTPC_GET_RESUME) + { + offset = statbuf.st_size; + } + else + { + offset = 0; + } + + /* Setup to receive the file */ + + ret = ftpc_recvinit(session, rname, xfrmode, offset); + if (ret != OK) + { + ndbg("ftpc_recvinit failed\n"); + goto errout_with_abspath; + } + + loutstream = fopen(abslpath, (offset > 0 || (how == FTPC_GET_APPEND)) ? "a" : "w"); + if (!loutstream) + { + ndbg("fopen failed: %d\n", errno); + goto errout_with_abspath; + } + + /* If the offset is non-zero, then seek to that offset in the file */ + + if (offset > 0) + { + ret = fseek(loutstream, offset, SEEK_SET); + if (ret != OK) + { + ndbg("fseek failed: %d\n", errno); + goto errout_with_outstream; + } + } + + /* And receive the new file data */ + + if (xfrmode == FTPC_XFRMODE_ASCII) + { + ret = ftpc_recvtext(session, session->data.instream, loutstream); + } + else + { + ret = ftpc_recvbinary(session, session->data.instream, loutstream); + } + + ftpc_sockclose(&session->data); + + if (ret == 0) + { + fptc_getreply(session); + } + + /* Check for success */ + + if (ret == OK && !FTPC_INTERRUPTED(session)) + { + fclose(loutstream); + free(abslpath); + return OK; + } + + /* Various error exits */ + +errout_with_outstream: + fclose(loutstream); +errout_with_abspath: + free(abslpath); + session->offset = 0; +errout: + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_recvtext + * + * Description: + * Receive a text file. + * + ****************************************************************************/ + +int ftpc_recvtext(FAR struct ftpc_session_s *session, + FAR FILE *rinstream, FAR FILE *loutstream) +{ + int ch; + + /* Read the next character from the incoming data stream */ + + while ((ch = fgetc(rinstream)) != EOF) + { + /* Is it a carriage return? Compress \r\n to \n */ + + if (ch == '\r') + { + /* Get the next character */ + + ch = fgetc(rinstream); + if (ch == EOF) + { + /* Ooops... */ + + (void)ftpc_xfrabort(session, rinstream); + return ERROR; + } + + /* If its not a newline, then keep the carriage return */ + + if (ch != '\n') + { + ungetc(ch, rinstream); + ch = '\r'; + } + } + + /* Then write the character to the output file */ + + if (fputc(ch, loutstream) == EOF) + { + (void)ftpc_xfrabort(session, loutstream); + return ERROR; + } + + /* Increase the actual size of the file by one */ + + session->size++; + } + + return OK; +} + + diff --git a/apps/netutils/ftpc/ftpc_getreply.c b/apps/netutils/ftpc/ftpc_getreply.c new file mode 100644 index 000000000..058eaf213 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_getreply.c @@ -0,0 +1,268 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_getreply.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdlib.h> +#include <string.h> +#include <debug.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_gets + ****************************************************************************/ + +static int ftpc_gets(struct ftpc_session_s *session) +{ + int ch; + int ndx = 0; + + /* Start wth an empty response string */ + + session->reply[0] = '\0'; + + /* Verify that the command channel is still connected */ + + if (!ftpc_sockconnected(&session->cmd)) + { + ndbg("Cmd channel disconnected\n"); + return ERROR; + } + + /* Loop until the full line is obtained */ + + for (;;) + { + /* Get the next character from incoming command stream */ + + ch = ftpc_sockgetc(&session->cmd); + + /* Check if the command stream was closed */ + + if (ch == EOF) + { + ndbg("EOF: Server closed command stream\n"); + ftpc_reset(session); + return ERROR; + } + + /* Handle embedded Telnet stuff */ + + else if (ch == TELNET_IAC) + { + /* Handle TELNET commands */ + + switch(ch = ftpc_sockgetc(&session->cmd)) + { + case TELNET_WILL: + case TELNET_WONT: + ch = ftpc_sockgetc(&session->cmd); + ftpc_sockprintf(&session->cmd, "%c%c%c", TELNET_IAC, TELNET_DONT, ch); + ftpc_sockflush(&session->cmd); + break; + + case TELNET_DO: + case TELNET_DONT: + ch = ftpc_sockgetc(&session->cmd); + ftpc_sockprintf(&session->cmd, "%c%c%c", TELNET_IAC, TELNET_WONT, ch); + ftpc_sockflush(&session->cmd); + break; + + default: + break; + } + + continue; + } + + /* Deal with carriage returns */ + + else if (ch == ISO_cr) + { + /* What follows the carriage return? */ + + ch = ftpc_sockgetc(&session->cmd); + if (ch == '\0') + { + /* If it is followed by a NUL then keep it */ + + ch = ISO_cr; + } + + /* If it is followed by a newline then break out of the loop. */ + + else if (ch == ISO_nl) + { + /* Newline terminates the reply */ + + break; + } + + /* If we did not lose the connection, then push the character + * following the carriage back on the "stack" and continue to + * examine it from scratch (if could be part of the Telnet + * protocol). + */ + + else if (ch != EOF) + { + ungetc(ch, session->cmd.instream); + continue; + } + } + + else if (ch == ISO_nl) + { + /* The ISO newline character terminates the string. Just break + * out of the loop. + */ + + break; + } + + /* Put the character into the response buffer. Is there space for + * another character in the reply buffer? + */ + + if (ndx < CONFIG_FTP_MAXREPLY) + { + /* Yes.. put the character in the reply buffer */ + + session->reply[ndx++] = (char)ch; + } + else + { + ndbg("Reply truncated\n"); + } + } + + session->reply[ndx] = '\0'; + session->code = atoi(session->reply); + return session->code; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_getreply + ****************************************************************************/ + +int fptc_getreply(struct ftpc_session_s *session) +{ + char tmp[5]="xxx "; + int ret; + + /* Set up a timeout */ + + if (session->replytimeo) + { + ret = wd_start(session->wdog, session->replytimeo, ftpc_timeout, 1, session); + } + + /* Get the next line from the server */ + + ret = ftpc_gets(session); + + /* Do we still have a connection? */ + + if (!ftpc_sockconnected(&session->cmd)) + { + /* No.. cancel the timer and return an error */ + + wd_cancel(session->wdog); + nvdbg("Lost connection\n"); + return ERROR; + } + + /* Did an error occur? */ + + if (ret < 0) + { + /* No.. cancel the timer and return an error */ + + wd_cancel(session->wdog); + nvdbg("ftpc_gets failed\n"); + return ERROR; + } + + nvdbg("Reply: %s\n", session->reply); + + if (session->reply[3] == '-') + { + /* Multi-line response */ + + strncpy(tmp, session->reply, 3); + do + { + if (ftpc_gets(session) == -1) + { + break; + } + + nvdbg("Reply: %s\n", session->reply); + } + while (strncmp(tmp, session->reply, 4) != 0); + } + + wd_cancel(session->wdog); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_help.c b/apps/netutils/ftpc/ftpc_help.c new file mode 100644 index 000000000..19041bc24 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_help.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_help.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_help + * + * Description: + * Request a list of available help commands. This implementation is + * fragementary and no ready for any real use at this time. + * + ****************************************************************************/ + +int ftpc_help(SESSION handle, FAR const char *arg) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + /* Send the HELP command with or without an argument */ + + if (arg) + { + ret = ftpc_cmd(session, "HELP %s", arg); + } + else + { + ret = ftpc_cmd(session, "HELP"); + } + + /* Logic is missing here to return the help string to the caller. The caller + * needs to call ftpc_getreply. + */ + + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_idle.c b/apps/netutils/ftpc/ftpc_idle.c new file mode 100644 index 000000000..95a94d233 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_idle.c @@ -0,0 +1,122 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_idle.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <debug.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_idle + * + * Description: + * This command will change the FTP server's idle time limit with the site + * idle ftp command. This is useful if the default time limit is too short + * for the transmission of files). + * + ****************************************************************************/ + +int ftpc_idle(SESSION handle, unsigned int idletime) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret = OK; + + /* Check if the server supports the SITE IDLE command */ + + if (!FTPC_HAS_IDLE(session)) + { + ndbg("Server does not support SITE IDLE\n"); + return ERROR; + } + + /* Did the caller provide an IDLE time? Or is this just a query for the + * current IDLE time setting? + */ + + if (idletime) + { + ret = ftpc_cmd(session, "SITE IDLE %u", idletime); + } + else + { + ret = ftpc_cmd(session, "SITE IDLE"); + } + + /* Check for "502 Command not implemented" or 500 "Unknown SITE command" */ + + if (session->code == 500 || session->code == 502) + { + /* Server does not support SITE IDLE */ + + ndbg("Server does not support SITE IDLE\n"); + FTPC_CLR_IDLE(session); + } + + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_internal.h b/apps/netutils/ftpc/ftpc_internal.h new file mode 100644 index 000000000..5c9d88951 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_internal.h @@ -0,0 +1,281 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_internal.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H +#define __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <sys/types.h> +#include <sys/socket.h> + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <time.h> +#include <wdog.h> + +#include <apps/ftpc.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* MISC definitions *********************************************************/ + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +/* Telnet-related definitions */ + +#define TELNET_DM 242 +#define TELNET_IP 244 +#define TELNET_IAC 255 +#define TELNET_WILL 251 +#define TELNET_WONT 252 +#define TELNET_DO 253 +#define TELNET_DONT 254 + +/* Session flag bits ********************************************************/ + +#define FTPC_FLAG_PASSIVE (1 << 0) /* Passive mode requested */ +#define FTPC_SESSION_FLAGS (0x0001) /* Persist throughout the session */ + +#define FTPC_FLAG_CONNECTED (1 << 1) /* Connected to host */ +#define FTPC_FLAG_LOGGEDIN (1 << 2) /* Logged in to host */ +#define FTPC_STATE_FLAGS (0x0006) /* State of connection */ + +#define FTPC_FLAG_MDTM (1 << 3) /* Host supports MDTM command */ +#define FTPC_FLAG_SIZE (1 << 4) /* Host supports SIZE command */ +#define FTPC_FLAG_PASV (1 << 5) /* Host supports PASV command */ +#define FTPC_FLAG_STOU (1 << 6) /* Host supports STOU command */ +#define FTPC_FLAG_CHMOD (1 << 7) /* Host supports SITE CHMOD command */ +#define FTPC_FLAG_IDLE (1 << 8) /* Host supports SITE IDLE command */ +#define FTPC_HOSTCAP_FLAGS (0x01f8) /* Host capabilities */ + +#define FTPC_FLAG_INTERRUPT (1 << 9) /* Transfer interrupted */ +#define FTPC_FLAG_PUT (1 << 10) /* Transfer is a PUT operation (upload) */ +#define FTPC_XFER_FLAGS (0x0600) /* Transfer related */ + +/* These are the bits to be set/cleared when the flags are reset */ + +#define FTPC_FLAGS_CLEAR (FTPC_STATE_FLAGS | FTPC_XFER_FLAGS) +#define FTPC_FLAGS_SET FTPC_HOSTCAP_FLAGS + +/* Macros to set bits */ + +#define FTPC_SET_CONNECTED(s) do { (s)->flags |= FTPC_FLAG_CONNECTED; } while (0) +#define FTPC_SET_LOGGEDIN(s) do { (s)->flags |= FTPC_FLAG_LOGGEDIN; } while (0) +#define FTPC_SET_MDTM(s) do { (s)->flags |= FTPC_FLAG_MDTM; } while (0) +#define FTPC_SET_SIZE(s) do { (s)->flags |= FTPC_FLAG_SIZE; } while (0) +#define FTPC_SET_PASV(s) do { (s)->flags |= FTPC_FLAG_PASV; } while (0) +#define FTPC_SET_STOU(s) do { (s)->flags |= FTPC_FLAG_STOU; } while (0) +#define FTPC_SET_CHMOD(s) do { (s)->flags |= FTPC_FLAG_CHMOD; } while (0) +#define FTPC_SET_IDLE(s) do { (s)->flags |= FTPC_FLAG_IDLE; } while (0) +#define FTPC_SET_INTERRUPT(s) do { (s)->flags |= FTPC_FLAG_INTERRUPT; } while (0) +#define FTPC_SET_PUT(s) do { (s)->flags |= FTPC_FLAG_PUT; } while (0) +#define FTPC_SET_PASSIVE(s) do { (s)->flags |= FTPC_FLAG_PASSIVE; } while (0) + +/* Macros to clear bits */ + +#define FTPC_CLR_CONNECTED(s) do { (s)->flags &= ~FTPC_FLAG_CONNECTED; } while (0) +#define FTPC_CLR_LOGGEDIN(s) do { (s)->flags &= ~FTPC_FLAG_LOGGEDIN; } while (0) +#define FTPC_CLR_MDTM(s) do { (s)->flags &= ~FTPC_FLAG_MDTM; } while (0) +#define FTPC_CLR_SIZE(s) do { (s)->flags &= ~FTPC_FLAG_SIZE; } while (0) +#define FTPC_CLR_PASV(s) do { (s)->flags &= ~FTPC_FLAG_PASV; } while (0) +#define FTPC_CLR_STOU(s) do { (s)->flags &= ~FTPC_FLAG_STOU; } while (0) +#define FTPC_CLR_CHMOD(s) do { (s)->flags &= ~FTPC_FLAG_CHMOD; } while (0) +#define FTPC_CLR_IDLE(s) do { (s)->flags &= ~FTPC_FLAG_IDLE; } while (0) +#define FTPC_CLR_INTERRUPT(s) do { (s)->flags &= ~FTPC_FLAG_INTERRUPT; } while (0) +#define FTPC_CLR_PUT(s) do { (s)->flags &= ~FTPC_FLAG_PUT; } while (0) +#define FTPC_CLR_PASSIVE(s) do { (s)->flags &= ~FTPC_FLAG_PASSIVE; } while (0) + +/* Macros to test bits */ + +#define FTPC_IS_CONNECTED(s) (((s)->flags & FTPC_FLAG_CONNECTED) != 0) +#define FTPC_IS_LOGGEDIN(s) (((s)->flags & FTPC_FLAG_LOGGEDIN) != 0) +#define FTPC_HAS_MDTM(s) (((s)->flags & FTPC_FLAG_MDTM) != 0) +#define FTPC_HAS_SIZE(s) (((s)->flags & FTPC_FLAG_SIZE) != 0) +#define FTPC_HAS_PASV(s) (((s)->flags & FTPC_FLAG_PASV) != 0) +#define FTPC_HAS_STOU(s) (((s)->flags & FTPC_FLAG_STOU) != 0) +#define FTPC_HAS_CHMOD(s) (((s)->flags & FTPC_FLAG_CHMOD) != 0) +#define FTPC_HAS_IDLE(s) (((s)->flags & FTPC_FLAG_IDLE) != 0) +#define FTPC_INTERRUPTED(s) (((s)->flags & FTPC_FLAG_INTERRUPT) != 0) +#define FTPC_IS_PUT(s) (((s)->flags & FTPC_FLAG_PUT) != 0) +#define FTPC_IS_PASSIVE(s) (((s)->flags & FTPC_FLAG_PASSIVE) != 0) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This structure represents the state of one socket connection */ + +struct ftpc_socket_s +{ + int sd; /* Socket descriptor */ + FILE *instream; /* Incoming stream */ + FILE *outstream; /* Outgoing stream */ + struct sockaddr_in laddr; /* Local address */ + bool connected; /* True: socket is connected */ +}; + +/* This structure represents the state of an FTP connection */ + +struct ftpc_session_s +{ + struct in_addr addr; /* Server/proxy IP address */ + struct ftpc_socket_s cmd; /* FTP command channel */ + struct ftpc_socket_s data; /* FTP data channel */ + WDOG_ID wdog; /* Timer */ + FAR char *uname; /* Login uname */ + FAR char *pwd; /* Login pwd */ + FAR char *initrdir; /* Initial remote directory */ + FAR char *homerdir; /* Remote home directory (currdir on startup) */ + FAR char *currdir; /* Remote current directory */ + FAR char *homeldir; /* Local home directory (PWD on startup) */ + pid_t pid; /* Task ID of FTP client */ + uint8_t xfrmode; /* Previous data transfer type (See FTPC_XFRMODE_* defines) */ + uint16_t port; /* Server/proxy port number (probably 21) */ + uint16_t flags; /* Connection flags (see FTPC_FLAGS_* defines) */ + uint16_t code; /* Last 3-digit reply code */ + uint32_t replytimeo; /* Server reply timeout (ticks) */ + uint32_t conntimeo; /* Connection timeout (ticks) */ + off_t offset; /* Transfer file offset */ + off_t size; /* Number of bytes transferred */ + + char reply[CONFIG_FTP_MAXREPLY+1]; /* Last reply string from server */ + char buffer[CONFIG_FTP_BUFSIZE]; /* Used to buffer file data during transfers */ +}; + +/* There is not yet any want to change the local working directly (an lcd + * command), but the following definition is provided to reserve the name + * for the storage location for the local current working directory. + */ + +#define curldir homeldir + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Inline Functions/Function-like Macros + ****************************************************************************/ + +#define ftpc_sockconnected(s) \ + ((s) && (s)->connected) +#define ftpc_connected(s) \ + (FTPC_IS_CONNECTED(session) && ftpc_sockconnected(&session->cmd)) +#define ftpc_loggedin(s) \ + (ftpc_connected(s) && FTPC_IS_LOGGEDIN(s)) + +#define ftpc_sockgetc(s) \ + fgetc((s)->instream) +#define ftpc_sockflush(s) \ + fflush((s)->outstream) +#define ftpc_sockvprintf(s,f,ap) \ + vfprintf((s)->outstream,f,ap) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/* Low-level string management */ + +EXTERN void ftpc_stripcrlf(FAR char *str); +EXTERN void ftpc_stripslash(FAR char *str); +EXTERN FAR char *ftpc_dequote(FAR const char *hostname); + +/* Connection helpers */ + +EXTERN int ftpc_reconnect(FAR struct ftpc_session_s *session); +EXTERN int ftpc_relogin(FAR struct ftpc_session_s *session); + +/* FTP helpers */ + +EXTERN void ftpc_reset(struct ftpc_session_s *session); +EXTERN int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...); +EXTERN int fptc_getreply(struct ftpc_session_s *session); +EXTERN FAR const char *ftpc_lpwd(void); +EXTERN int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode); +EXTERN FAR char *ftpc_absrpath(FAR struct ftpc_session_s *session, + FAR const char *relpath); +EXTERN FAR char *ftpc_abslpath(FAR struct ftpc_session_s *session, + FAR const char *relpath); + +/* Socket helpers */ + +EXTERN int ftpc_sockinit(FAR struct ftpc_socket_s *sock); +EXTERN void ftpc_sockclose(FAR struct ftpc_socket_s *sock); +EXTERN int ftpc_sockconnect(FAR struct ftpc_socket_s *sock, + FAR struct sockaddr_in *addr); +EXTERN int ftpc_sockgetsockname(FAR struct ftpc_socket_s *sock, + FAR struct sockaddr_in *sa); +EXTERN int ftpc_sockaccept(FAR struct ftpc_socket_s *sock); +EXTERN int ftpc_socklisten(FAR struct ftpc_socket_s *sock); +EXTERN void ftpc_sockcopy(FAR struct ftpc_socket_s *dest, + FAR const struct ftpc_socket_s *src); + +/* Socket I/O helpers */ + +EXTERN int ftpc_sockprintf(FAR struct ftpc_socket_s *sock, const char *fmt, ...); +EXTERN void ftpc_timeout(int argc, uint32_t arg1, ...); + +/* Transfer helpers */ + +EXTERN int ftpc_xfrinit(FAR struct ftpc_session_s *session); +EXTERN int ftpc_recvtext(FAR struct ftpc_session_s *session, + FAR FILE *rinstream, FAR FILE *loutstream); +EXTERN int ftpc_waitdata(FAR struct ftpc_session_s *session, + FAR FILE *stream, bool rdwait); + +EXTERN void ftpc_xfrreset(struct ftpc_session_s *session); +EXTERN int ftpc_xfrabort(FAR struct ftpc_session_s *session, + FAR FILE *stream); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H */ diff --git a/apps/netutils/ftpc/ftpc_listdir.c b/apps/netutils/ftpc/ftpc_listdir.c new file mode 100644 index 000000000..1bfda8234 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_listdir.c @@ -0,0 +1,412 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_listdir.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <libgen.h> +#include <errno.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef void (*callback_t)(FAR const char *name, FAR void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_dircount + * + * Description: + * This callback simply counts the number of names in the directory. + * + ****************************************************************************/ + +static void ftpc_dircount(FAR const char *name, FAR void *arg) +{ + FAR unsigned int *dircount = (FAR unsigned int *)arg; + (*dircount)++; +} + +/**************************************************************************** + * Name: ftpc_addname + * + * Description: + * This callback adds a name to the directory listing. + * + ****************************************************************************/ + +static void ftpc_addname(FAR const char *name, FAR void *arg) +{ + FAR struct ftpc_dirlist_s *dirlist = (FAR struct ftpc_dirlist_s *)arg; + unsigned int nnames = dirlist->nnames; + dirlist->name[nnames] = strdup(name); + dirlist->nnames = nnames + 1; +} + +/**************************************************************************** + * Name: ftpc_nlstparse + * + * Description: + * Parse the NLST directory response. The NLST response consists of a + * sequence of pathnames. Each pathname is terminated by \r\n. + * + * If a pathname starts with a slash, it represents the pathname. If a + * pathname does not start with a slash, it represents the pathname obtained + * by concatenating the pathname of the directory and the pathname. + * + * IF NLST of directory /pub produces foo\r\nbar\r\n, it refers to the + * pathnames /pub/foo and /pub/bar. + * + ****************************************************************************/ + +static void ftpc_nlstparse(FAR FILE *instream, callback_t callback, + FAR void *arg) +{ + char buffer[CONFIG_FTP_MAXPATH+1]; + + /* Read every filename from the temporary file */ + + for (;;) + { + /* Read the next line from the file */ + + if (!fgets(buffer, CONFIG_FTP_MAXPATH, instream)) + { + break; + } + + /* Remove any trailing CR-LF from the line */ + + ftpc_stripcrlf(buffer); + + /* Check for empty file names */ + + if (buffer[0] == '\0') + { + break; + } + nvdbg("File: %s\n", buffer); + + /* Perform the callback operation */ + + callback(buffer, arg); + } +} + +/**************************************************************************** + * Name: ftpc_recvdir + * + * Description: + * Get the directory listing. + * + ****************************************************************************/ + +static int ftpc_recvdir(FAR struct ftpc_session_s *session, + FAR FILE *outstream) +{ + int ret; + + /* Verify that we are still connected to the server */ + + if (!ftpc_connected(session)) + { + ndbg("Not connected to server\n"); + return ERROR; + } + + /* Setup for the transfer */ + + ftpc_xfrreset(session); + ret = ftpc_xfrinit(session); + if (ret != OK) + { + return ERROR; + } + + /* Send the "NLST" command. Normally the server responds with a mark + * using code 150: + * + * - "150 File status okay; about to open data connection" + * + * It then stops accepting new connections, attempts to + * send the contents of the directory over the data connection, and + * closes the data connection. + */ + + ret = ftpc_cmd(session, "NLST"); + if (ret != OK) + { + return ERROR; + } + + /* In active mode, we need to accept a connection on the data socket + * (in passive mode, we have already connected the data channel to + * the FTP server). + */ + + if (!FTPC_IS_PASSIVE(session)) + { + ret = ftpc_sockaccept(&session->data); + if (ret != OK) + { + ndbg("ftpc_sockaccept() failed: %d\n", errno); + return ERROR; + } + } + + /* Receive the NLST directory list */ + + ret = ftpc_recvtext(session, session->data.instream, outstream); + ftpc_sockclose(&session->data); + if (ret != OK) + { + return ERROR; + } + + /* Get the server reply. After closing the data connection, the should + * accept the request with: + * + * - "226 Closing data connection" if the entire directory was + * successfully transmitted; + * + * Or reject it with: + * + * - "425 Can't open data connection" if no TCP connection was established + * - "426 - Connection closed; transfer aborted" if the TCP connection was + * established but then broken by the client or by network failure + * - "451 - Requested action aborted: local error in processing" if the + * server had trouble reading the directory from disk. + * + * The server may reject the LIST or NLST request (with code 450 or 550) + * without first responding with a mark. In this case the server does not + * touch the data connection. + */ + + fptc_getreply(session); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_listdir + * + * Description: + * Get a simple directory listing using NLST: + * + * NLST [<SP> <pathname>] <CRLF> + * + * We could do much, much more here using the LIST or MLST/MLSD commands, + * but the parsing is a bitch. See http://cr.yp.to/ftpparse.html + * + * NOTE: We expect to receive only well structured directory paths. Tilde + * expansion "~/xyz" and relative pathes (abc/def) because we do have + * special knowledge about the home and current directories. But otherwise + * the pathes are expected to be pre-sanitized: No . or .. in paths, + * no '//' in paths, etc. + * + ****************************************************************************/ + +FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle, + FAR const char *dirpath) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + struct ftpc_dirlist_s *dirlist; + FILE *filestream; + FAR char *absrpath; + FAR char *tmpfname; + bool iscurrdir; + unsigned int nnames; + int allocsize; + int ret; + + /* Get the absolute path to the directory */ + + absrpath = ftpc_absrpath(session, dirpath); + ftpc_stripslash(absrpath); + + /* Is the directory also the remote current working directory? */ + + iscurrdir = (strcmp(absrpath, session->currdir) == 0); + + /* Create a temporary file to hold the directory listing */ + + asprintf(&tmpfname, "%s/TMP%d.dat", CONFIG_FTP_TMPDIR, getpid()); + filestream = fopen(tmpfname, "w+"); + if (!filestream) + { + ndbg("Failed to create %s: %d\n", tmpfname, errno); + free(absrpath); + free(tmpfname); + return NULL; + } + + /* "CWD" first so that we get the directory contents, not the + * directory itself. + */ + + if (!iscurrdir) + { + ret = ftpc_cmd(session, "CWD %s", absrpath); + if (ret != OK) + { + ndbg("CWD to %s failed\n", absrpath); + } + } + + /* Send the NLST command with no arguments to get the entire contents of + * the directory. + */ + + ret = ftpc_recvdir(session, filestream); + + /* Go back to the correct current working directory */ + + if (!iscurrdir) + { + int tmpret = ftpc_cmd(session, "CWD %s", session->currdir); + if (tmpret != OK) + { + ndbg("CWD back to to %s failed\n", session->currdir); + } + } + + /* Did we successfully receive the directory listing? */ + + dirlist = NULL; + if (ret == OK) + { + /* Count the number of names in the temporary file */ + + rewind(filestream); + nnames = 0; + + ftpc_nlstparse(filestream, ftpc_dircount, &nnames); + if (!nnames) + { + ndbg("Nothing found in directory\n"); + goto errout; + } + nvdbg("nnames: %d\n", nnames); + + /* Allocate and initialize a directory container */ + + allocsize = SIZEOF_FTPC_DIRLIST(nnames); + dirlist = (struct ftpc_dirlist_s *)malloc(allocsize); + if (!dirlist) + { + ndbg("Failed to allocate dirlist\n"); + goto errout; + } + + /* Then copy all of the directory strings into the container */ + + rewind(filestream); + dirlist->nnames = 0; + + ftpc_nlstparse(filestream, ftpc_addname, dirlist); + DEBUGASSERT(nnames == dirlist->nnames); + } + +errout: + fclose(filestream); + free(absrpath); + unlink(tmpfname); + free(tmpfname); + return dirlist; +} + +/**************************************************************************** + * Name: ftpc_dirfree + * + * Description: + * Release the allocated directory listing. + * + ****************************************************************************/ + +void ftpc_dirfree(FAR struct ftpc_dirlist_s *dirlist) +{ + int i; + + if (dirlist) + { + /* Free each directory name in the directory container */ + + for (i = 0; i < dirlist->nnames; i++) + { + /* NULL means that the caller stole the string */ + + if (dirlist->name[i]) + { + free(dirlist->name[i]); + } + } + + /* Then free the container itself */ + + free(dirlist); + } +} + diff --git a/apps/netutils/ftpc/ftpc_login.c b/apps/netutils/ftpc/ftpc_login.c new file mode 100644 index 000000000..be899a074 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_login.c @@ -0,0 +1,215 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_login.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <string.h> +#include <errno.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_login + * + * Description: + * Log into the server + * + ****************************************************************************/ + +int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int err; + int ret; + + /* Verify that we are connected to a server */ + + if (!ftpc_connected(session)) + { + ndbg("Not connected\n"); + err = ENOTCONN; + goto errout_with_err; + } + + /* Verify that we are not already logged in to the server */ + + if (ftpc_loggedin(session)) + { + ndbg("Already logged in\n"); + err = EINVAL; + goto errout_with_err; + } + + /* Save the login parameter */ + + session->uname = ftpc_dequote(login->uname); + session->pwd = ftpc_dequote(login->pwd); + session->initrdir = ftpc_dequote(login->rdir); + + /* Is passive mode requested? */ + + FTPC_CLR_PASSIVE(session); + if (login->pasv) + { + nvdbg("Setting passive mode\n"); + FTPC_SET_PASSIVE(session); + } + + /* The (Re-)login to the server */ + + ret = ftpc_relogin(session); + if (ret != OK) + { + ndbg("login failed: %d\n", errno); + goto errout; + } + + return OK; + +errout_with_err: + set_errno(err); +errout: + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_relogin + * + * Description: + * Log in again after a loss of connection + * + ****************************************************************************/ + +int ftpc_relogin(FAR struct ftpc_session_s *session) +{ + int err; + int ret; + + /* Log into the server. First send the USER command. The server may accept + * USER with: + * + * - "230 User logged in, proceed" meaning that the client has permission to + * access files under that username + * - "331 "User name okay, need password" or "332 Need account for login" + * meaning that permission might be granted after a PASS request. + * + * Or the server may reject USER with: + * + * - "530 Not logged in" meaning that the username is unacceptable. + * + * In practice, the server does not check the username until after a PASS + * request + */ + + FTPC_CLR_LOGGEDIN(session); + ret = ftpc_cmd(session, "USER %s", session->uname); + if (ret != OK) + { + ndbg("USER %s cmd failed: %d\n", session->uname, errno); + return ERROR; + } + + /* Send the PASS command with the passed. The server may accept PASS with: + * + * - "230 User logged in, proceed" meaning that the client has permission to + * access files under that username + * - "202 Command not implemented, superfluous at this site" meaning that + * permission was already granted in response to USER + * - "332 Need account for login" meaning that permission might be granted + * after an ACCT request. + * + * The server may reject PASS with: + * + * - "503 Bad sequence of commands" if the previous request was not USER + * - "530 - Not logged in" if this username and password are unacceptable. + */ + + ret = ftpc_cmd(session, "PASS %s", session->pwd); + if (ret != OK) + { + ndbg("PASS %s cmd failed: %d\n", session->pwd, errno); + return ret; + } + + /* We are logged in.. the current working directory on login is our "home" + * directory. + */ + + FTPC_SET_LOGGEDIN(session); + session->homerdir = ftpc_rpwd((SESSION)session); + session->currdir = strdup(session->homerdir); + + /* If the user has requested a special start up directory, then change to + * that directory now. + */ + + if (session->initrdir) + { + ftpc_chdir((SESSION)session, session->initrdir); + } + + return OK; +} diff --git a/apps/netutils/ftpc/ftpc_mkdir.c b/apps/netutils/ftpc/ftpc_mkdir.c new file mode 100644 index 000000000..59684f07d --- /dev/null +++ b/apps/netutils/ftpc/ftpc_mkdir.c @@ -0,0 +1,105 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_mkdir.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdlib.h> +#include <string.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_mkdir + * + * Description: + * Creates the named directory on the remote server. + * + ****************************************************************************/ + +int ftpc_mkdir(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + char *ptr; + int ret; + + ptr = strdup(path); + ftpc_stripslash(ptr); + + /* Send the MKD request. The MKD request asks the server to create a new + * directory. The server accepts the MKD with either: + * + * - "257 PATHNAME created" that includes the pathname of the directory + * - "250 - Requested file action okay, completed" if the directory was + * successfully created. + * + * The server reject MKD with: + * + * - "550 Requested action not taken" if the creation failed. + */ + + ret = ftpc_cmd(session, "MKD %s", ptr); + free(ptr); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_noop.c b/apps/netutils/ftpc/ftpc_noop.c new file mode 100644 index 000000000..48d9ccafd --- /dev/null +++ b/apps/netutils/ftpc/ftpc_noop.c @@ -0,0 +1,85 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_noop.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_noop + * + * Description: + * No operation command. Using NOOP allows us to make sure that commands + * are passed over the control connection without changing the status of + * any data transaction or server status. This is useful for (1) + * maintaining connections during long IDLE times and (2) It can also be + * used as a harmless way of detecting timeouts. + * + ****************************************************************************/ + +int ftpc_noop(SESSION handle) +{ + return ftpc_cmd((FAR struct ftpc_session_s *)handle, "NOOP"); +} diff --git a/apps/netutils/ftpc/ftpc_putfile.c b/apps/netutils/ftpc/ftpc_putfile.c new file mode 100644 index 000000000..517a988b1 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_putfile.c @@ -0,0 +1,481 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_putfile.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <libgen.h> +#include <errno.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_sendbinary + * + * Description: + * Send a binary file to the remote host. + * + ****************************************************************************/ + +static int ftpc_sendbinary(FAR struct ftpc_session_s *session, + FAR FILE *linstream, FILE *routstream) +{ + ssize_t nread; + ssize_t nwritten; + + /* Loop until the entire file is sent */ + + for (;;) + { + /* Read data from the file */ + + nread = fread(session->buffer, sizeof(char), CONFIG_FTP_BUFSIZE, linstream); + if (nread <= 0) + { + /* nread == 0 is just EOF */ + + if (nread < 0) + { + (void)ftpc_xfrabort(session, linstream); + return ERROR; + } + + /* Return success */ + + return OK; + } + + /* Send the data */ + + nwritten = fwrite(session->buffer, sizeof(char), nread, routstream); + if (nwritten != nread) + { + (void)ftpc_xfrabort(session, routstream); + + /* Return failue */ + + return ERROR; + } + + /* Increment the size of the file sent */ + + session->size += nread; + } +} + +/**************************************************************************** + * Name: ftpc_sendtext + * + * Description: + * Send a text file to the remote host. + * + ****************************************************************************/ + +static int ftpc_sendtext(FAR struct ftpc_session_s *session, + FAR FILE *linstream, FAR FILE *routstream) +{ + int ch; + int ret = OK; + + /* Write characters one at a time. */ + + while ((ch = fgetc(linstream)) != EOF) + { + /* If it is a newline, send a carriage return too */ + + if (ch == '\n') + { + if (fputc('\r', routstream) == EOF) + { + (void)ftpc_xfrabort(session, routstream); + ret = ERROR; + break; + } + + /* Increment the size of the file sent */ + + session->size++; + } + + /* Send the character */ + + if (fputc(ch, routstream) == EOF) + { + (void)ftpc_xfrabort(session, routstream); + ret = ERROR; + break; + } + + /* Increment the size of the file sent */ + + session->size++; + } + + return ret; +} + +/**************************************************************************** + * Name: ftpc_sendfile + * + * Description: + * Send the file to the remote host. + * + ****************************************************************************/ + +static int ftpc_sendfile(struct ftpc_session_s *session, const char *path, + FILE *stream, uint8_t how, uint8_t xfrmode) +{ + long offset = session->offset; +#ifdef CONFIG_DEBUG + FAR char *rname; + FAR char *str; + int len; +#endif + int ret; + + session->offset = 0; + + /* Were we asked to store a file uniquely? Does the host support the STOU + * command? + */ + + if (how == FTPC_PUT_UNIQUE && !FTPC_HAS_STOU(session)) + { + /* We cannot store a file uniquely */ + + return ERROR; + } + + ftpc_xfrreset(session); + FTPC_SET_PUT(session); + + /* Initialize for the transfer */ + + ret = ftpc_xfrinit(session); + if (ret != OK) + { + return ERROR; + } + + ftpc_xfrmode(session, xfrmode); + + /* The REST command sets the start position in the file. Some servers + * allow REST immediately before STOR for binary files. + */ + + if (offset > 0) + { + ret = ftpc_cmd(session, "REST %ld", offset); + session->size = offset; + } + + /* Send the file using STOR, STOU, or APPE: + * + * - STOR request asks the server to receive the contents of a file from + * the data connection already established by the client. + * - APPE is just like STOR except that, if the file already exists, the + * server appends the client's data to the file. + * - STOU is just like STOR except that it asks the server to create a + * file under a new pathname selected by the server. If the server + * accepts STOU, it provides the pathname in a human-readable format in + * the text of its response. + */ + + switch (how) + { + case FTPC_PUT_UNIQUE: + { + ret = ftpc_cmd(session, "STOU %s", path); + + /* Check for "502 Command not implemented" */ + + if (session->code == 502) + { + /* The host does not support the STOU command */ + + FTPC_CLR_STOU(session); + return ERROR; + } + + /* Get the remote filename from the response */ + +#ifdef CONFIG_DEBUG + str = strstr(session->reply, " for "); + if (str) + { + str += 5; + len = strlen(str); + if (len) + { + if (*str == '\'') + { + rname = strndup(str+1, len-3); + } + else + { + rname = strndup(str, len-1); + nvdbg("Unique filename is: %s\n", rname); + } + free(rname); + } + } +#endif + } + break; + + case FTPC_PUT_APPEND: + ret = ftpc_cmd(session, "APPE %s", path); + break; + + case FTPC_PUT_NORMAL: + default: + ret = ftpc_cmd(session, "STOR %s", path); + break; + } + + /* If the server is willing to create a new file under that name, or + * replace an existing file under that name, it responds with a mark + * using code 150: + * + * - "150 File status okay; about to open data connection" + * + * It then attempts to read the contents of the file from the data + * connection, and closes the data connection. Finally it accepts the STOR + * with: + * + * - "226 Closing data connection" if the entire file was successfully + * received and stored + * + * Or rejects the STOR with: + * + * - "425 Can't open data connection" if no TCP connection was established + * - "426 Connection closed; transfer aborted" if the TCP connection was + * established but then broken by the client or by network failure + * - "451 Requested action aborted: local error in processing", + * "452 - Requested action not taken", or "552 Requested file action + * aborted" if the server had trouble saving the file to disk. + * + * The server may reject the STOR request with: + * + * - "450 Requested file action not taken", "452 - Requested action not + * taken" or "553 Requested action not taken" without first responding + * with a mark. + */ + + /* In active mode, we need to accept a connection on the data socket + * (in passive mode, we have already connected the data channel to + * the FTP server). + */ + + if (!FTPC_IS_PASSIVE(session)) + { + ret = ftpc_sockaccept(&session->data); + if (ret != OK) + { + ndbg("Data connection not accepted\n"); + return ERROR; + } + } + + /* Then perform the data transfer */ + + if (xfrmode == FTPC_XFRMODE_ASCII) + { + ret = ftpc_sendtext(session, stream, session->data.outstream); + } + else + { + ret = ftpc_sendbinary(session, stream, session->data.outstream); + } + + ftpc_sockflush(&session->data); + ftpc_sockclose(&session->data); + + if (ret == 0) + { + fptc_getreply(session); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_putfile + * + * Description: + * Put a file on the remote host. + * + ****************************************************************************/ + +int ftp_putfile(SESSION handle, const char *lname, const char *rname, + uint8_t how, uint8_t xfrmode) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + FAR char *abslpath; + struct stat statbuf; + FILE *finstream; + int ret; + + /* Don't call this with a NULL local file name */ + + DEBUGASSERT(lname); + + /* If the remote name is not specified, then it is assumed to the same as + * the local file name. + */ + + if (!rname) + { + rname = lname; + } + + /* Get the full path to the local file */ + + abslpath = ftpc_abslpath(session, lname); + if (!abslpath) + { + ndbg("ftpc_abslpath(%s) failed: %d\n", errno); + goto errout; + } + + /* Make sure that the local file exists */ + + ret = stat(abslpath, &statbuf); + if (ret != OK) + { + ndbg("stat(%s) failed: %d\n", errno); + goto errout_with_abspath; + } + + /* Make sure that the local name does not refer to a directory */ + + if (S_ISDIR(statbuf.st_mode)) + { + ndbg("%s is a directory\n", abslpath); + goto errout_with_abspath; + } + + /* Open the local file for reading */ + + finstream = fopen(abslpath, "r"); + if (!finstream) + { + ndbg("fopen() failed: %d\n", errno); + goto errout_with_abspath; + } + + /* Are we resuming a transfer? */ + + session->offset = 0; + if (how == FTPC_PUT_RESUME) + { + /* Yes... Get the size of the file. This will only work if the + * server supports the SIZE command. + */ + + session->offset = ftpc_filesize(session, rname); + if (session->offset == (off_t)ERROR) + { + ndbg("Failed to get size of remote file: %s\n", rname); + goto errout_with_instream; + } + else + { + /* Seek to the offset in the file corresponding to the size + * that we have already sent. + */ + + ret = fseek(finstream, session->offset, SEEK_SET); + if (ret != OK) + { + ndbg("fseek failed: %d\n", errno); + goto errout_with_instream; + } + } + } + + /* Send the file */ + + ret = ftpc_sendfile(session, rname, finstream, how, xfrmode); + if (ret == OK) + { + fclose(finstream); + free(abslpath); + return OK; + } + + /* Various error exits */ + +errout_with_instream: + fclose(finstream); +errout_with_abspath: + free(abslpath); +errout: + return ERROR; +} diff --git a/apps/netutils/ftpc/ftpc_quit.c b/apps/netutils/ftpc/ftpc_quit.c new file mode 100644 index 000000000..25ec8b16f --- /dev/null +++ b/apps/netutils/ftpc/ftpc_quit.c @@ -0,0 +1,92 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_quit.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <time.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_quit + * + * Description: + * Ends the FTP session with the remote computer and exits ftp + * + ****************************************************************************/ + +int ftpc_quit(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret = OK; + + if (ftpc_connected(session)) + { + session->replytimeo = 10 * CLOCKS_PER_SEC; + ret = ftpc_cmd(session, "QUIT"); + } + + ftpc_disconnect(handle); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_rename.c b/apps/netutils/ftpc/ftpc_rename.c new file mode 100644 index 000000000..f2355fdd5 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_rename.c @@ -0,0 +1,134 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_rename.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdlib.h> +#include <string.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_rename + * + * Description: + * Rename a file on the remote server. + * + ****************************************************************************/ + +int ftpc_rename(SESSION handle, FAR const char *oldname, FAR const char *newname) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + char *oldcopy; + char *newcopy; + int ret; + + oldcopy = strdup(oldname); + ftpc_stripslash(oldcopy); + + /* A RNFR request asks the server to begin renaming a file. A typical + * server accepts RNFR with: + * + * - "350 Requested file action pending further information" if the file + * exists + * + * Or rejects RNFR with: + * + * - "450 Requested file action not taken" + * - "550 Requested action not taken" + */ + + ret = ftpc_cmd(session, "RNFR %s", oldcopy); + if (ret != OK) + { + free(oldcopy); + return ERROR; + } + + newcopy = strdup(newname); + ftpc_stripslash(newcopy); + + /* A RNTO request asks the server to finish renaming a file. RNTO must + * come immediately after RNFR; otherwise the server may reject RNTO with: + * + * - "503 Bad sequence of commands" + * + * A typical server accepts RNTO with: + * + * - "250 Requested file action okay, completed" if the file was renamed + * successfully + * + * Or rejects RMD with: + * + * - "550 Requested action not taken" + * - "553 Requested action not taken" + */ + + ret = ftpc_cmd(session, "RNTO %s", newcopy); + + free(oldcopy); + free(newcopy); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_response.c b/apps/netutils/ftpc/ftpc_response.c new file mode 100644 index 000000000..275b48123 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_response.c @@ -0,0 +1,84 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_response.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <string.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_response + * + * Description: + * Return the response string from the last command. This is allocated + * memory that must be freed using free() when it is no longer needed. + * + ****************************************************************************/ + +FAR char *ftpc_response(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + return strndup(session->reply, CONFIG_FTP_MAXREPLY); +} diff --git a/apps/netutils/ftpc/ftpc_rmdir.c b/apps/netutils/ftpc/ftpc_rmdir.c new file mode 100644 index 000000000..4a2c27f48 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_rmdir.c @@ -0,0 +1,103 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_rmdir.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdlib.h> +#include <string.h> +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_rmdir + * + * Description: + * Deletes the named directory on the remote server. + * + ****************************************************************************/ +int ftpc_rmdir(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + char *ptr; + int ret; + + ptr = strdup(path); + ftpc_stripslash(ptr); + + /* An RMD request asks the server to remove a directory. A typical server + * accepts RMD with: + * + * - "250 Requested file action okay, completed" if the directory was + * successfully removed + * + * Or rejects RMD with: + * + * - "550 Requested action not taken" if the removal failed. + */ + + ret = ftpc_cmd(session, "RMD %s", ptr); + free(ptr); + return ret; +} + diff --git a/apps/netutils/ftpc/ftpc_rpwd.c b/apps/netutils/ftpc/ftpc_rpwd.c new file mode 100644 index 000000000..091a12944 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_rpwd.c @@ -0,0 +1,151 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_rpwd.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdlib.h> +#include <string.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_rpwd + * + * Descripton: + * Returns the current working directory on the remote server. + * + ****************************************************************************/ + +FAR char *ftpc_rpwd(SESSION handle) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + FAR char *start; + FAR char *end; + FAR char *pwd; + FAR char *ptr; + int len; + int ret; + + /* Send the PWD command */ + + ret = ftpc_cmd(session, "PWD"); + + /* Response is like: 257 "/home/gnutt" (from vsftpd). + * + * Extract the quoated path name into allocated memory. + */ + + start = strchr(session->reply, '\"'); + if (!start) + { + ndbg("Opening quote not found\n"); + return NULL; + } + start++; + + end = strchr(start, '\"'); + if (!end) + { + ndbg("Closing quote not found\n"); + return NULL; + } + + /* Allocate memory for the path name: + * + * Reply: 257 "/home/gnutt" + * ^start ^end + * + * len = end - start + 1 = 11 (+ NUL terminator) + */ + + len = end - start + 1; + pwd = (char *)malloc(len + 1); + if (!pwd) + { + ndbg("Failed to allocate string\n"); + return NULL; + } + + /* Copy the string into the allocated memory */ + + memcpy(pwd, start, len); + pwd[len] = '\0'; + + /* Remove any trailing slashes that the server may have added */ + + ftpc_stripslash(pwd); + + /* Change DOS style directory separator ('\') to UNIX style ('/') */ + + for (ptr = pwd; *ptr; ptr++) + { + if (*ptr == '\\') + { + *ptr = '/'; + } + } + return pwd; +} diff --git a/apps/netutils/ftpc/ftpc_socket.c b/apps/netutils/ftpc/ftpc_socket.c new file mode 100644 index 000000000..4ec022bd0 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_socket.c @@ -0,0 +1,370 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_socket.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" +#include <sys/socket.h> + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <debug.h> +#include <errno.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_sockinit + * + * Description: + * Initialize a socket. Create the socket and "wrap" it as C standard + * incoming and outgoing streams. + * + ****************************************************************************/ + +int ftpc_sockinit(FAR struct ftpc_socket_s *sock) +{ + /* Initialize the socket structure */ + + memset(sock, 0, sizeof(struct ftpc_socket_s)); + + /* Create a socket descriptor */ + + sock->sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock->sd < 0) + { + ndbg("socket() failed: %d\n", errno); + goto errout; + } + + /* Call fdopen to "wrap" the socket descriptor as an input stream using C + * buffered I/O. + */ + + sock->instream = fdopen(sock->sd, "r"); + if (!sock->instream) + { + ndbg("fdopen() failed: %d\n", errno); + goto errout_with_sd; + } + + /* Call fdopen to "wrap" the socket descriptor as an output stream using C + * buffered I/O. + */ + + sock->outstream = fdopen(sock->sd, "w"); + if (!sock->outstream) + { + ndbg("fdopen() failed: %d\n", errno); + goto errout_with_instream; + } + + return OK; + +/* Close the instream. NOTE: Since the underlying socket descriptor is + * *not* dup'ed, the following close should fail harmlessly. + */ + +errout_with_instream: + fclose(sock->instream); + sock->instream = NULL; +errout_with_sd: + close(sock->sd); + sock->sd = -1; +errout: + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_sockclose + * + * Description: + * Close a socket + * + ****************************************************************************/ + +void ftpc_sockclose(struct ftpc_socket_s *sock) +{ + /* Note that the same underlying socket descriptor is used for both streams. + * There should be harmless failures on the second fclose and the close. + */ + + fclose(sock->instream); + fclose(sock->outstream); + close(sock->sd); + memset(sock, 0, sizeof(struct ftpc_socket_s)); + sock->sd = -1; +} + +/**************************************************************************** + * Name: ftpc_sockconnect + * + * Description: + * Connect the socket to the host. On a failure, the caller should call. + * ftpc_sockclose() to clean up. + * + ****************************************************************************/ + +int ftpc_sockconnect(struct ftpc_socket_s *sock, struct sockaddr_in *addr) +{ + int ret; + + /* Connect to the server */ + + ret = connect(sock->sd, (struct sockaddr *)addr, sizeof(struct sockaddr)); + if (ret < 0) + { + ndbg("connect() failed: %d\n", errno); + return ERROR; + } + + /* Get the local address of the socket */ + + ret = ftpc_sockgetsockname(sock, &sock->laddr); + if (ret < 0) + { + ndbg("ftpc_sockgetsockname() failed: %d\n", errno); + return ERROR; + } + + sock->connected = true; + return OK; +} + +/**************************************************************************** + * Name: ftpc_sockcopy + * + * Description: + * Copy the socket state from one location to another. + * + ****************************************************************************/ + +void ftpc_sockcopy(FAR struct ftpc_socket_s *dest, + FAR const struct ftpc_socket_s *src) +{ + memcpy(&dest->laddr, &src->laddr, sizeof(struct sockaddr_in)); + dest->connected = ftpc_sockconnected(src); +} + +/**************************************************************************** + * Name: ftpc_sockaccept + * + * Description: + * Accept a connection on the data socket. This function is onlly used + * in active mode. + * + * In active mode FTP the client connects from a random port (N>1023) to the + * FTP server's command port, port 21. Then, the client starts listening to + * port N+1 and sends the FTP command PORT N+1 to the FTP server. The server + * will then connect back to the client's specified data port from its local + * data port, which is port 20. In passive mode FTP the client initiates + * both connections to the server, solving the problem of firewalls filtering + * the incoming data port connection to the client from the server. When + * opening an FTP connection, the client opens two random ports locally + * (N>1023 and N+1). The first port contacts the server on port 21, but + * instead of then issuing a PORT command and allowing the server to connect + * back to its data port, the client will issue the PASV command. The result + * of this is that the server then opens a random unprivileged port (P > + * 1023) and sends the PORT P command back to the client. The client then + * initiates the connection from port N+1 to port P on the server to transfer + * data. + * + ****************************************************************************/ + +int ftpc_sockaccept(FAR struct ftpc_socket_s *sock) +{ + struct sockaddr addr; + socklen_t addrlen; + + /* Any previous socket should have been uninitialized (0) or explicitly + * closed (-1). But the path to this function may include a call to + * ftpc_sockinit(). If so... close that socket and call accept to + * get a new one. + */ + + if (sock->sd > 0) + { + ftpc_sockclose(sock); + } + + addrlen = sizeof(addr); + sock->sd = accept(sock->sd, &addr, &addrlen); + if (sock->sd == -1) + { + ndbg("accept() failed: %d\n", errno); + return ERROR; + } + + memcpy(&sock->laddr, &addr, sizeof(sock->laddr)); + + /* Create in/out C buffer I/O streams on the data channel. First, + * create the incoming buffered stream. + */ + + sock->instream = fdopen(sock->sd, "r"); + if (!sock->instream) + { + ndbg("fdopen() failed: %d\n", errno); + goto errout_with_sd; + } + + /* Create the outgoing stream */ + + sock->outstream = fdopen(sock->sd, "w"); + if (!sock->outstream) + { + ndbg("fdopen() failed: %d\n", errno); + goto errout_with_instream; + } + + return OK; + +/* Close the instream. NOTE: Since the underlying socket descriptor is + * *not* dup'ed, the following close should fail harmlessly. + */ + +errout_with_instream: + fclose(sock->instream); + sock->instream = NULL; +errout_with_sd: + close(sock->sd); + sock->sd = -1; + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_socklisten + * + * Description: + * Bind the socket to local address and wait for connection from the server. + * + ****************************************************************************/ + +int ftpc_socklisten(struct ftpc_socket_s *sock) +{ + unsigned int addrlen = sizeof(sock->laddr); + int ret; + + /* Bind the local socket to the local address */ + + sock->laddr.sin_port = 0; + ret = bind(sock->sd, (struct sockaddr *)&sock->laddr, addrlen); + if (ret < 0) + { + ndbg("bind() failed: %d\n", errno); + return ERROR; + } + + /* Wait for the connection to the server */ + + if (listen(sock->sd, 1) == -1) + { + return ERROR; + } + + /* Then get the local address selected by NuttX */ + + ret = ftpc_sockgetsockname(sock, &sock->laddr); + return ret; +} + +/**************************************************************************** + * Name: ftpc_sockprintf + * + * Description: + * printf to a socket stream + * + ****************************************************************************/ + +int ftpc_sockprintf(struct ftpc_socket_s *sock, const char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = vfprintf(sock->outstream, fmt, ap); + va_end(ap); + return r; +} + +/**************************************************************************** + * Name: ftpc_sockgetsockname + * + * Description: + * Get the address of the local socket + * + ****************************************************************************/ + +int ftpc_sockgetsockname(FAR struct ftpc_socket_s *sock, + FAR struct sockaddr_in *addr) +{ + socklen_t len = sizeof(struct sockaddr_in); + int ret; + + ret = getsockname(sock->sd, (FAR struct sockaddr *)addr, &len); + if (ret < 0) + { + ndbg("getsockname failed: %d\n", errno); + return ERROR; + } + return OK; +} diff --git a/apps/netutils/ftpc/ftpc_transfer.c b/apps/netutils/ftpc/ftpc_transfer.c new file mode 100644 index 000000000..464cd2a60 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_transfer.c @@ -0,0 +1,517 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_transfer.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/stat.h> +#include <sys/time.h> + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <poll.h> +#include <ctype.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftp_pasvmode + * + * Description: + * Enter passive mode. + * + * In active mode FTP the client connects from a random port (N>1023) to the + * FTP server's command port, port 21. Then, the client starts listening to + * port N+1 and sends the FTP command PORT N+1 to the FTP server. The server + * will then connect back to the client's specified data port from its local + * data port, which is port 20. In passive mode FTP the client initiates + * both connections to the server, solving the problem of firewalls filtering + * the incoming data port connection to the client from the server. When + * opening an FTP connection, the client opens two random ports locally + * (N>1023 and N+1). The first port contacts the server on port 21, but + * instead of then issuing a PORT command and allowing the server to connect + * back to its data port, the client will issue the PASV command. The result + * of this is that the server then opens a random unprivileged port (P > + * 1023) and sends the PORT P command back to the client. The client then + * initiates the connection from port N+1 to port P on the server to transfer + * data. + * + ****************************************************************************/ + +static int ftp_pasvmode(struct ftpc_session_s *session, + uint8_t addrport[6]) +{ + int tmpap[6]; + char *ptr; + int nscan; + int ret; + int i; + + /* Does this host support the PASV command */ + + if (!FTPC_HAS_PASV(session)) + { + ndbg("Host doesn't support passive mode\n"); + return ERROR; + } + + /* Request passive mode. The server normally accepts PASV with code 227. + * Its response is a single line showing the IP address of the server and + * the TCP port number where the server is accepting connections. + */ + + ret = ftpc_cmd(session, "PASV"); + if (ret < 0 || !ftpc_connected(session)) + { + return ERROR; + } + + /* Skip over any leading stuff before address begins */ + + ptr = session->reply + 4; + while (!isdigit((int)*ptr)) + { + ptr++; + } + + /* The response is then 6 integer values: four representing the + * IP address and two representing the port number. + */ + + nscan = sscanf(ptr, "%d,%d,%d,%d,%d,%d", + &tmpap[0], &tmpap[1], &tmpap[2], + &tmpap[3], &tmpap[4], &tmpap[5]); + if (nscan != 6) + { + ndbg("Error parsing PASV reply: '%s'\n", session->reply); + return ERROR; + } + + /* Then copy the sscanf'ed values as bytes */ + + + for (i = 0; i < 6; i++) + { + addrport[i] = (uint8_t)(tmpap[i] & 0xff); + } + + return OK; +} + +/**************************************************************************** + * Name: ftpc_abspath + * + * Description: + * Get the absolute path to a file, handling tilde expansion. + * + ****************************************************************************/ + +static FAR char *ftpc_abspath(FAR struct ftpc_session_s *session, + FAR const char *relpath, FAR const char *homedir, + FAR const char *curdir) +{ + FAR char *ptr = NULL; + int ret = OK; + + /* If no relative path was provide, then use the current working directory */ + + if (!relpath) + { + return strdup(curdir); + } + + /* Handle tilde expansion */ + + if (relpath[0] == '~') + { + /* Is the relative path only '~' */ + + if (relpath[1] == '\0') + { + return strdup(homedir); + } + + /* No... then a '/' better follow the tilde */ + + else if (relpath[1] == '/') + { + ret = asprintf(&ptr, "%s%s", homedir, &relpath[1]); + } + + /* Hmmm... this pretty much guaranteed to fail */ + + else + { + ptr = strdup(relpath); + } + } + + /* No tilde expansion. Check for a path relative to the current + * directory. + */ + + else if (strncmp(relpath, "./", 2) == 0) + { + ret = asprintf(&ptr, "%s%s", curdir, relpath+1); + } + + /* Check for an absolute path */ + + else if (relpath[0] == '/' && relpath[1] == ':' && relpath[2] == '\\') + { + ptr = strdup(relpath); + } + + /* Assume it a relative path */ + + else + { + ret = asprintf(&ptr, "%s/%s", curdir, relpath); + } + + return ptr; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_xfrinit + * + * Description: + * Perform common transfer setup logic. + * + ****************************************************************************/ + +int ftpc_xfrinit(FAR struct ftpc_session_s *session) +{ + struct sockaddr_in addr; + uint8_t addrport[6]; + uint8_t *paddr; + uint8_t *pport; + int ret; + + /* We must be connected to initiate a transfer */ + + if (!ftpc_connected(session)) + { + ndbg("Not connected\n"); + goto errout; + } + + /* Initialize the data channel */ + + ret = ftpc_sockinit(&session->data); + if (ret != OK) + { + ndbg("ftpc_sockinit() failed: %d\n", errno); + goto errout; + } + + /* Duplicate the address and connection information of the command channel */ + + ftpc_sockcopy(&session->data, &session->cmd); + + /* Should we enter passive mode? */ + + if (FTPC_IS_PASSIVE(session)) + { + /* Yes.. going passive. */ + + ret = ftp_pasvmode(session, addrport); + if (ret != OK) + { + ndbg("ftp_pasvmode() failed: %d\n", errno); + goto errout_with_data; + } + + /* Configure the data socket */ + + ftpc_sockgetsockname(&session->cmd, &addr); + memcpy(&addr.sin_addr, addrport, 4); + memcpy(&addr.sin_port, addrport+4, 2); + + /* Connect the data socket */ + + ret = ftpc_sockconnect(&session->data, &addr); + if (ret < 0) + { + ndbg("ftpc_sockconnect() failed: %d\n", errno); + goto errout_with_data; + } + } + else + { + /* Wait for the connection to be established */ + + ftpc_socklisten(&session->data); + + /* Then send our local data channel address to the server */ + + paddr = (uint8_t *)&session->data.laddr.sin_addr; + pport = (uint8_t *)&session->data.laddr.sin_port; + + ret = ftpc_cmd(session, "PORT %d,%d,%d,%d,%d,%d", + paddr[0], paddr[1], paddr[2], + paddr[3], pport[0], pport[1]); + if (ret < 0) + { + ndbg("ftpc_cmd() failed: %d\n", errno); + goto errout_with_data; + } + } + return OK; + + errout_with_data: + ftpc_sockclose(&session->data); + errout: + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_xfrreset + * + * Description: + * Reset transfer variables + * + ****************************************************************************/ + +void ftpc_xfrreset(struct ftpc_session_s *session) +{ + session->size = 0; + session->flags &= ~FTPC_XFER_FLAGS; +} + +/**************************************************************************** + * Name: ftpc_xfrmode + * + * Description: + * Select ASCII or Binary transfer mode + * + ****************************************************************************/ + +int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode) +{ + int ret; + + /* Check if we have already selected the requested mode */ + + DEBUGASSERT(xfrmode != FTPC_XFRMODE_UNKNOWN); + if (session->xfrmode != xfrmode) + { + /* Send the TYPE request to control the binary flag. Parameters for the + * TYPE request include: + * + * A: Turn the binary flag off. + * A N: Turn the binary flag off. + * I: Turn the binary flag on. + * L 8: Turn the binary flag on. + * + * The server accepts the TYPE request with code 200. + */ + + ret = ftpc_cmd(session, "TYPE %c", xfrmode == FTPC_XFRMODE_ASCII ? 'A' : 'I'); + session->xfrmode = xfrmode; + } + return OK; +} + +/**************************************************************************** + * Name: ftpc_xfrabort + * + * Description: + * Abort a transfer in progress + * + ****************************************************************************/ + +int ftpc_xfrabort(FAR struct ftpc_session_s *session, FAR FILE *stream) +{ + FAR struct pollfd fds; + int ret; + + /* Make sure that we are still connected */ + + if (!ftpc_connected(session)) + { + return ERROR; + } + + /* Check if there is data waiting to be read from the cmd channel */ + + fds.fd = session->cmd.sd; + fds.events = POLLIN; + ret = poll(&fds, 1, 0); + if (ret > 0) + { + /* Read data from command channel */ + + nvdbg("Flush cmd channel data\n"); + while (stream && fread(session->buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0); + return OK; + } + + FTPC_SET_INTERRUPT(session); + + /* Send the Telnet interrupt sequence to abort the transfer: + * <IAC IP><IAC DM>ABORT<CR><LF> + */ + + nvdbg("Telnet ABORt sequence\n"); + ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_IP); /* Interrupt process */ + ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_DM); /* Telnet synch signal */ + ftpc_sockprintf(&session->cmd, "ABOR\r\n"); /* Abort */ + ftpc_sockflush(&session->cmd); + + /* Read remaining bytes from connection */ + + while (stream && fread(session->buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0); + while(stream && fread(session->buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0) + + /* Get the ABORt reply */ + + fptc_getreply(session); + + /* Expected replys are: "226 Closing data connection" or + * "426 Connection closed; transfer aborted" + */ + + if (session->code != 226 && session->code != 426) + { + nvdbg("Expected 226 or 426 reply\n"); + } + else + { + /* Get the next reply */ + + fptc_getreply(session); + + /* Expected replys are: or "225 Data connection open; no transfer in progress" + * "226 Closing data connection" + */ + + if (session->code != 226 && session->code != 225) + { + nvdbg("Expected 225 or 226 reply\n"); + } + } + + return ERROR; +} + +/**************************************************************************** + * Name: ftpc_timeout + * + * Description: + * A timeout occurred -- either on a specific command or while waiting + * for a reply. + * + * NOTE: + * This function executes in the context of a timer interrupt handler. + * + ****************************************************************************/ + +void ftpc_timeout(int argc, uint32_t arg1, ...) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)arg1; + + nlldbg("Timeout!\n"); + DEBUGASSERT(argc == 1 && session); + kill(session->pid, CONFIG_FTP_SIGNAL); +} + +/**************************************************************************** + * Name: ftpc_absrpath + * + * Description: + * Get the absolute path to a remote file, handling tilde expansion. + * + ****************************************************************************/ + +FAR char *ftpc_absrpath(FAR struct ftpc_session_s *session, + FAR const char *relpath) +{ + FAR char *absrpath = ftpc_abspath(session, relpath, + session->homerdir, session->currdir); + nvdbg("%s -> %s\n", relpath, absrpath); + return absrpath; +} + +/**************************************************************************** + * Name: ftpc_abslpath + * + * Description: + * Get the absolute path to a local file, handling tilde expansion. + * + ****************************************************************************/ + +FAR char *ftpc_abslpath(FAR struct ftpc_session_s *session, + FAR const char *relpath) +{ + FAR char *abslpath = ftpc_abspath(session, relpath, + session->homeldir, session->curldir); + nvdbg("%s -> %s\n", relpath, abslpath); + return abslpath; +} + + diff --git a/apps/netutils/ftpc/ftpc_unlink.c b/apps/netutils/ftpc/ftpc_unlink.c new file mode 100644 index 000000000..cf6733eca --- /dev/null +++ b/apps/netutils/ftpc/ftpc_unlink.c @@ -0,0 +1,96 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_unlink.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <apps/ftpc.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_unlink + * + * Descripton: + * Delete the given file from the remote server. + * + ****************************************************************************/ + +int ftpc_unlink(SESSION handle, FAR const char *path) +{ + FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; + int ret; + + /* A DELE request asks the server to remove a regular file. A typical server + * accepts DELE with: + * + * - "250 Requested file action okay, completed" if the file was + * successfully removed + * + * Or rejects RMD with: + * + * - "550 Requested action not taken" f the removal failed. + */ + + ret = ftpc_cmd(session, "DELE %s", path); + return ret; +} diff --git a/apps/netutils/ftpc/ftpc_utils.c b/apps/netutils/ftpc/ftpc_utils.c new file mode 100644 index 000000000..21a466c00 --- /dev/null +++ b/apps/netutils/ftpc/ftpc_utils.c @@ -0,0 +1,266 @@ +/**************************************************************************** + * apps/netutils/ftpc/ftpc_utils.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "ftpc_config.h" + +#include <stdlib.h> +#include <string.h> + +#include "ftpc_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_nibble + * + * Description: + * Convert a ASCII hex 'digit' to binary + * + ****************************************************************************/ + +int ftpc_nibble(char ch) +{ + if (ch >= '0' && ch <= '9') + { + return (unsigned int)ch - '0'; + } + else if (ch >= 'A' && ch <= 'F') + { + return (unsigned int)ch - 'A' + 10; + } + else if (ch >= 'a' && ch <= 'f') + { + return (unsigned int)ch - 'a' + 10; + } + return ERROR; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftpc_reset + * + * Description: + * Reset the FTP session. + * + ****************************************************************************/ + +void ftpc_reset(struct ftpc_session_s *session) +{ + ftpc_sockclose(&session->data); + ftpc_sockclose(&session->cmd); + free(session->uname); + session->uname = NULL; + free(session->pwd); + session->pwd = NULL; + free(session->initrdir); + session->initrdir = NULL; + session->flags &= ~FTPC_FLAGS_CLEAR; + session->flags |= FTPC_FLAGS_SET; + session->xfrmode = FTPC_XFRMODE_UNKNOWN; + session->code = 0; + session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; + session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC; +} + +/**************************************************************************** + * Name: ftpc_lpwd + * + * Description: + * Return the local current working directory. NOTE: This is a peek at + * a global copy. The caller should call strdup if it wants to keep it. + * + ****************************************************************************/ + +FAR const char *ftpc_lpwd(void) +{ +#ifndef CONFIG_DISABLE_ENVIRON + FAR const char *val; + + val = getenv("PWD"); + if (!val) + { + val = CONFIG_FTP_TMPDIR; + } + return val; +#else + return CONFIG_FTP_TMPDIR; +#endif +} + +/**************************************************************************** + * Name: ftpc_stripcrlf + * + * Description: + * Strip any trailing carriage returns or line feeds from a string (by + * overwriting them with NUL characters). + * + ****************************************************************************/ + +void ftpc_stripcrlf(FAR char *str) +{ + FAR char *ptr; + int len; + + if (str) + { + len = strlen(str); + if (len > 0) + { + ptr = str + len - 1; + while (*ptr == '\r' || *ptr == '\n') + { + *ptr = '\0'; + ptr--; + } + } + } +} + +/**************************************************************************** + * Name: ftpc_stripslash + * + * Description: + * Strip any trailing slashes from a string (by overwriting them with NUL + * characters. + * + ****************************************************************************/ + +void ftpc_stripslash(FAR char *str) +{ + FAR char *ptr; + int len; + + if (str) + { + len = strlen(str); + if (len > 1) + { + ptr = str + len - 1; + if (*ptr == '/') + { + *ptr = '\0'; + } + } + } +} + +/**************************************************************************** + * Name: ftpc_dequote + * + * Description: + * Convert quoted hexadecimal constants to binary values. + * + ****************************************************************************/ + +FAR char *ftpc_dequote(FAR const char *str) +{ + FAR char *allocstr = NULL; + FAR char *ptr; + int ms; + int ls; + int len; + + if (str) + { + /* Allocate space for a modifiable copy of the string */ + + len = strlen(str); + allocstr = (FAR char*)malloc(len+1); + if (allocstr) + { + /* Search the string */ + + ptr = allocstr; + while (*str) + { + /* Check for a quoted hex value */ + + if (str[0] == '%') + { + /* Extract the hex value */ + + ms = ftpc_nibble(str[1]); + if (ms >= 0) + { + ls = ftpc_nibble(str[2]); + if (ls >= 0) + { + /* Save the binary value and skip ahead by 3 */ + + *ptr++ = (char)(ms << 8 | ls); + str += 3; + continue; + } + } + } + + /* Just transfer the character */ + + *ptr++ = *str++; + } + + /* NUL terminate */ + + *ptr = '\0'; + } + } + + return allocstr; +} diff --git a/apps/netutils/resolv/Makefile b/apps/netutils/resolv/Makefile new file mode 100644 index 000000000..32d0896e2 --- /dev/null +++ b/apps/netutils/resolv/Makefile @@ -0,0 +1,97 @@ +############################################################################ +# apps/netutils/resolv/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Resolver library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_UDP),y) +CSRCS = resolv.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/resolv/resolv.c b/apps/netutils/resolv/resolv.c new file mode 100644 index 000000000..db9e00085 --- /dev/null +++ b/apps/netutils/resolv/resolv.c @@ -0,0 +1,440 @@ +/**************************************************************************** + * uip-resolv.c + * DNS host name to IP address resolver. + * + * The uIP DNS resolver functions are used to lookup a hostname and + * map it to a numerical IP address. It maintains a list of resolved + * hostnames that can be queried with the resolv_lookup() + * function. New hostnames can be resolved using the resolv_query() + * function. + * + * When a hostname has been resolved (or found to be non-existant), + * the resolver code calls a callback function called resolv_found() + * that must be implemented by the module that uses the resolver. + * + * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based heavily on portions of uIP: + * + * Author: Adam Dunkels <adam@dunkels.com> + * Copyright (c) 2002-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <errno.h> +#include <debug.h> + +#include <sys/socket.h> +#include <arpa/inet.h> + +#include <apps/netutils/resolv.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifndef CONFIG_NET_RESOLV_ENTRIES +#define RESOLV_ENTRIES 4 +#else /* CONFIG_NET_RESOLV_ENTRIES */ +#define RESOLV_ENTRIES CONFIG_NET_RESOLV_ENTRIES +#endif /* CONFIG_NET_RESOLV_ENTRIES */ + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +/* The maximum number of retries when asking for a name */ + +#define MAX_RETRIES 8 + +#define DNS_FLAG1_RESPONSE 0x80 +#define DNS_FLAG1_OPCODE_STATUS 0x10 +#define DNS_FLAG1_OPCODE_INVERSE 0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE 0x04 +#define DNS_FLAG1_TRUNC 0x02 +#define DNS_FLAG1_RD 0x01 +#define DNS_FLAG2_RA 0x80 +#define DNS_FLAG2_ERR_MASK 0x0f +#define DNS_FLAG2_ERR_NONE 0x00 +#define DNS_FLAG2_ERR_NAME 0x03 + +#define SEND_BUFFER_SIZE 64 +#define RECV_BUFFER_SIZE 64 + +#ifdef CONFIG_NET_IPv6 +#define ADDRLEN sizeof(struct sockaddr_in6) +#else +#define ADDRLEN sizeof(struct sockaddr_in) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The DNS message header */ + +struct dns_hdr +{ + uint16_t id; + uint8_t flags1, flags2; + uint16_t numquestions; + uint16_t numanswers; + uint16_t numauthrr; + uint16_t numextrarr; +}; + +/* The DNS answer message structure */ + +struct dns_answer +{ + /* DNS answer record starts with either a domain name or a pointer + * to a name already present somewhere in the packet. + */ + + uint16_t type; + uint16_t class; + uint16_t ttl[2]; + uint16_t len; +#ifdef CONFIG_NET_IPv6 + struct in6_addr ipaddr; +#else + struct in_addr ipaddr; +#endif +}; + +struct namemap +{ + uint8_t state; + uint8_t tmr; + uint8_t retries; + uint8_t seqno; + uint8_t err; + char name[32]; +#ifdef CONFIG_NET_IPv6 + struct in6_addr ipaddr; +#else + struct in_addr ipaddr; +#endif +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint8_t g_seqno; +static int g_sockfd = -1; +#ifdef CONFIG_NET_IPv6 +static struct sockaddr_in6 g_dnsserver; +#else +static struct sockaddr_in g_dnsserver; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Walk through a compact encoded DNS name and return the end of it. */ + +static unsigned char *parse_name(unsigned char *query) +{ + unsigned char n; + + do + { + n = *query++; + + while(n > 0) + { + ++query; + --n; + } + } + while(*query != 0); + return query + 1; +} + +/* Runs through the list of names to see if there are any that have + * not yet been queried and, if so, sends out a query. + */ + +#ifdef CONFIG_NET_IPv6 +static int send_query(const char *name, struct sockaddr_in6 *addr) +#else +static int send_query(const char *name, struct sockaddr_in *addr) +#endif +{ + register struct dns_hdr *hdr; + char *query; + char *nptr; + const char *nameptr; + uint8_t seqno = g_seqno++; + static unsigned char endquery[] = {0, 0, 1, 0, 1}; + char buffer[SEND_BUFFER_SIZE]; + int n; + + hdr = (struct dns_hdr*)buffer; + memset(hdr, 0, sizeof(struct dns_hdr)); + hdr->id = htons(seqno); + hdr->flags1 = DNS_FLAG1_RD; + hdr->numquestions = HTONS(1); + query = buffer + 12; + + /* Convert hostname into suitable query format. */ + + nameptr = name - 1; + do + { + nameptr++; + nptr = query++; + for (n = 0; *nameptr != '.' && *nameptr != 0; nameptr++) + { + *query++ = *nameptr; + n++; + } + *nptr = n; + } + while(*nameptr != 0); + + memcpy(query, endquery, 5); + return sendto(g_sockfd, buffer, query + 5 - buffer, 0, (struct sockaddr*)addr, ADDRLEN); +} + +/* Called when new UDP data arrives */ + +#ifdef CONFIG_NET_IPv6 +#error "Not implemented" +#else +int recv_response(struct sockaddr_in *addr) +#endif +{ + unsigned char *nameptr; + char buffer[RECV_BUFFER_SIZE]; + struct dns_answer *ans; + struct dns_hdr *hdr; + uint8_t nquestions; + uint8_t nanswers; + int ret; + + /* Receive the response */ + + ret = recv(g_sockfd, buffer, RECV_BUFFER_SIZE, 0); + if (ret < 0) + { + return ret; + } + + hdr = (struct dns_hdr *)buffer; + + dbg( "ID %d\n", htons(hdr->id)); + dbg( "Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE); + dbg( "Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK); + dbg( "Num questions %d, answers %d, authrr %d, extrarr %d\n", + htons(hdr->numquestions), htons(hdr->numanswers), + htons(hdr->numauthrr), htons(hdr->numextrarr)); + + /* Check for error. If so, call callback to inform */ + + if ((hdr->flags2 & DNS_FLAG2_ERR_MASK) != 0) + { + return ERROR; + } + + /* We only care about the question(s) and the answers. The authrr + * and the extrarr are simply discarded. + */ + + nquestions = htons(hdr->numquestions); + nanswers = htons(hdr->numanswers); + + /* Skip the name in the question. XXX: This should really be + * checked agains the name in the question, to be sure that they + * match. + */ + + nameptr = parse_name((unsigned char *)buffer + 12) + 4; + + for (; nanswers > 0; nanswers--) + { + /* The first byte in the answer resource record determines if it + * is a compressed record or a normal one. + */ + + if (*nameptr & 0xc0) + { + /* Compressed name. */ + + nameptr +=2; + dbg("Compressed anwser\n"); + } + else + { + /* Not compressed name. */ + nameptr = parse_name(nameptr); + } + + ans = (struct dns_answer *)nameptr; + dbg("Answer: type %x, class %x, ttl %x, length %x\n", + htons(ans->type), htons(ans->class), (htons(ans->ttl[0]) << 16) | htons(ans->ttl[1]), + htons(ans->len)); + + /* Check for IP address type and Internet class. Others are discarded. */ + + if (ans->type == HTONS(1) && ans->class == HTONS(1) && ans->len == HTONS(4)) + { + dbg("IP address %d.%d.%d.%d\n", + (ans->ipaddr.s_addr >> 24 ) & 0xff, + (ans->ipaddr.s_addr >> 16 ) & 0xff, + (ans->ipaddr.s_addr >> 8 ) & 0xff, + (ans->ipaddr.s_addr ) & 0xff); + + /* XXX: we should really check that this IP address is the one + * we want. + */ + + addr->sin_addr.s_addr = ans->ipaddr.s_addr; + return OK; + } + else + { + nameptr = nameptr + 10 + htons(ans->len); + } + } + return ERROR; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* Get the binding for name. */ + +#ifdef CONFIG_NET_IPv6 +int resolv_query(FAR const char *name, FAR struct sockaddr_in6 *addr) +#else +int resolv_query(FAR const char *name, FAR struct sockaddr_in *addr) +#endif +{ + int retries; + int ret; + + /* Loop while receive timeout errors occur and there are remaining retries */ + + for (retries = 0; retries < 3; retries++) + { + if (send_query(name, addr) < 0) + { + return ERROR; + } + + ret = recv_response(addr); + if (ret >= 0) + { + /* Response received successfully */ + + return OK; + } + + else if (errno != EAGAIN) + { + /* Some failure other than receive timeout occurred */ + + return ERROR; + } + } + + return ERROR; +} + +/* Obtain the currently configured DNS server. */ + +#ifdef CONFIG_NET_IPv6 +void resolv_getserver(struct in6_addr *dnsserver) +#else +void resolv_getserver(struct in_addr *dnsserver) +#endif +{ +#ifdef CONFIG_NET_IPv6 + memcpy(dnsserver, &g_dnsserver.sin6_addr, ADDRLEN); +#else + dnsserver->s_addr = g_dnsserver.sin_addr.s_addr; +#endif +} + +/* Configure which DNS server to use for queries */ + +#ifdef CONFIG_NET_IPv6 +void resolv_conf(const struct in6_addr *dnsserver) +#else +void resolv_conf(const struct in_addr *dnsserver) +#endif +{ + g_dnsserver.sin_family = AF_INET; + g_dnsserver.sin_port = HTONS(53); +#ifdef CONFIG_NET_IPv6 + memcpy(&g_dnsserver.sin6_addr, dnsserver, ADDRLEN); +#else + g_dnsserver.sin_addr.s_addr = dnsserver->s_addr; +#endif +} + +/* Initalize the resolver. */ + +int resolv_init(void) +{ + struct timeval tv; + g_sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (g_sockfd < 0) + { + return ERROR; + } + + /* Set up a receive timeout */ + + tv.tv_sec = 30; + tv.tv_usec = 0; + if (setsockopt(g_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) < 0) + { + close(g_sockfd); + g_sockfd = -1; + return ERROR; + } + + return OK; +} diff --git a/apps/netutils/smtp/Makefile b/apps/netutils/smtp/Makefile new file mode 100644 index 000000000..758e436f3 --- /dev/null +++ b/apps/netutils/smtp/Makefile @@ -0,0 +1,97 @@ +############################################################################ +# apps/netutils/smtp/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# SMTP Library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_TCP),y) +CSRCS += smtp.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/smtp/smtp.c b/apps/netutils/smtp/smtp.c new file mode 100644 index 000000000..d758c6f6b --- /dev/null +++ b/apps/netutils/smtp/smtp.c @@ -0,0 +1,376 @@ +/**************************************************************************** + * apps/netutitls/smtp/smtp.c + * smtp SMTP E-mail sender + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Heavily leveraged from uIP 1.0 which also has a BSD-like license: + * + * The Simple Mail Transfer Protocol (SMTP) as defined by RFC821 is + * the standard way of sending and transfering e-mail on the + * Internet. This simple example implementation is intended as an + * example of how to implement protocols in uIP, and is able to send + * out e-mail but has not been extensively tested. + * + * Author: Adam Dunkels <adam@dunkels.com> + * Copyright (c) 2004, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <semaphore.h> +#include <sys/socket.h> + +#include <net/uip/uip.h> +#include <apps/netutils/smtp.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define SMTP_INPUT_BUFFER_SIZE 512 + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +#define ISO_period 0x2e + +#define ISO_2 0x32 +#define ISO_3 0x33 +#define ISO_4 0x34 +#define ISO_5 0x35 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure represents the state of a single SMTP transaction */ + +struct smtp_state +{ + uint8_t state; + bool connected; + sem_t sem; + uip_ipaddr_t smtpserver; + const char *localhostname; + const char *to; + const char *cc; + const char *from; + const char *subject; + const char *msg; + int msglen; + int sentlen; + int textlen; + int sendptr; + char buffer[SMTP_INPUT_BUFFER_SIZE]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_smtp220[] = "220"; +static const char g_smtpcrnlperiodcrnl[] = "\r\n.\r\n"; +static const char g_smtpdata[] = "DATA\r\n"; +static const char g_smtpfrom[] = "From: "; +static const char g_smtphelo[] = "HELO "; +static const char g_smtpmailfrom[] = "MAIL FROM: "; +static const char g_smtpquit[] = "QUIT\r\n"; +static const char g_smtprcptto[] = "RCPT TO: "; +static const char g_smtpsubject[] = "Subject: "; +static const char g_smtpto[] = "To: "; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline int smtp_send_message(int sockfd, struct smtp_state *psmtp) +{ + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } + + if (strncmp(psmtp->buffer, g_smtp220, strlen(g_smtp220)) != 0) + { + return ERROR; + } + + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", g_smtphelo, psmtp->localhostname); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } + + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } + + if (psmtp->buffer[0] != ISO_2) + { + return ERROR; + } + + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", g_smtpmailfrom, psmtp->from); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } + + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } + + if (psmtp->buffer[0] != ISO_2) + { + return ERROR; + } + + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", g_smtprcptto, psmtp->to); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } + + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } + + if (psmtp->buffer[0] != ISO_2) + { + return ERROR; + } + + if (psmtp->cc != 0) + { + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", g_smtprcptto, psmtp->cc); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } + + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } + + if (psmtp->buffer[0] != ISO_2) + { + return ERROR; + } + } + + if (send(sockfd, g_smtpdata, strlen(g_smtpdata), 0) < 0) + { + return ERROR; + } + + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } + + if (psmtp->buffer[0] != ISO_3) + { + return ERROR; + } + + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", g_smtpto, psmtp->to); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } + + if (psmtp->cc != 0) + { + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", g_smtpto, psmtp->cc); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } + } + + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", g_smtpfrom, psmtp->from); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } + + snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", g_smtpsubject, psmtp->subject); + if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0) + { + return ERROR; + } + + if (send(sockfd, psmtp->msg, psmtp->msglen, 0) < 0) + { + return ERROR; + } + + if (send(sockfd, g_smtpcrnlperiodcrnl, strlen(g_smtpcrnlperiodcrnl), 0) < 0) + { + return ERROR; + } + + if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0) + { + return ERROR; + } + + if (psmtp->buffer[0] != ISO_2) + { + return ERROR; + } + + if (send(sockfd, g_smtpquit, strlen(g_smtpquit), 0) < 0) + { + return ERROR; + } + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* Specificy an SMTP server and hostname. + * + * This function is used to configure the SMTP module with an SMTP server and + * the hostname of the host. + * + * lhostname - The hostname of the local, uIP host. + * + * paddr - A pointer to the IP address of the SMTP server to be + * configured. + */ + +void smtp_configure(void *handle, const char *lhostname, + const uip_ipaddr_t *paddr) +{ + struct smtp_state *psmtp = (struct smtp_state *)handle; + psmtp->localhostname = lhostname; + uip_ipaddr_copy(psmtp->smtpserver, paddr); +} + +/* Send an e-mail. + * + * to - The e-mail address of the receiver of the e-mail. + * cc - The e-mail address of the CC: receivers of the e-mail. + * from - The e-mail address of the sender of the e-mail. + * subject - The subject of the e-mail. + * msg - The actual e-mail message. + * msglen - The length of the e-mail message. + */ + +int smtp_send(void *handle, const char *to, const char *cc, const char *from, + const char *subject, const char *msg, int msglen) +{ + struct smtp_state *psmtp = (struct smtp_state *)handle; + struct sockaddr_in server; + int sockfd; + int ret; + + /* Setup */ + + psmtp->connected = true; + psmtp->to = to; + psmtp->cc = cc; + psmtp->from = from; + psmtp->subject = subject; + psmtp->msg = msg; + psmtp->msglen = msglen; + + /* Create a socket */ + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + { + return ERROR; + } + + /* Connect to server. First we have to set some fields in the + * 'server' structure. The system will assign me an arbitrary + * local port that is not in use. + */ + + server.sin_family = AF_INET; + memcpy(&server.sin_addr.s_addr, &psmtp->smtpserver, sizeof(in_addr_t)); + server.sin_port = HTONS(25); + + if (connect(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) + { + close(sockfd); + return ERROR; + } + + /* Send the message */ + + ret = smtp_send_message(sockfd, psmtp); + + close(sockfd); + return ret; +} + +void *smtp_open(void) +{ + /* Allocate the handle */ + + struct smtp_state *psmtp = (struct smtp_state *)malloc(sizeof(struct smtp_state)); + if (psmtp) + { + /* Initialize the handle */ + + memset(psmtp, 0, sizeof(struct smtp_state)); + (void)sem_init(&psmtp->sem, 0, 0); + } + return (void*)psmtp; +} + +void smtp_close(void *handle) +{ + struct smtp_state *psmtp = (struct smtp_state *)handle; + if (psmtp) + { + sem_destroy(&psmtp->sem); + free(psmtp); + } +} diff --git a/apps/netutils/telnetd/Makefile b/apps/netutils/telnetd/Makefile new file mode 100644 index 000000000..cba7f0c70 --- /dev/null +++ b/apps/netutils/telnetd/Makefile @@ -0,0 +1,97 @@ +############################################################################ +# apps/netutils/telnetd/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Telnet daemon + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_TCP),y) +CSRCS += telnetd.c shell.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/telnetd/README.txt b/apps/netutils/telnetd/README.txt new file mode 100644 index 000000000..24fcba7d5 --- /dev/null +++ b/apps/netutils/telnetd/README.txt @@ -0,0 +1,7 @@ +This directory is here for historical reasons. Nothing contained in this +directory is currently used by NuttX. This directly contains a functional +port of the tiny uIP shell. In the NuttX environment, the NuttShell (at +apps/nshlib) supercedes this tiny shell and also supports telnetd. + +This example is retained here for reference purposes only. + diff --git a/apps/netutils/telnetd/shell.c b/apps/netutils/telnetd/shell.c new file mode 100644 index 000000000..93fd11601 --- /dev/null +++ b/apps/netutils/telnetd/shell.c @@ -0,0 +1,139 @@ +/**************************************************************************** + * netutils/telnetd/telnetd.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * This is a leverage of similar logic from uIP: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <string.h> +#include "shell.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define SHELL_PROMPT "uIP 1.0> " + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct ptentry_s +{ + char *commandstr; + void (* pfunc)(void *handle, char *str); +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void parse(void *handle, register char *str, struct ptentry_s *t); +static void help(void *handle, char *str); +static void unknown(void *handle, char *str); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct ptentry_s g_parsetab[] = +{ + {"stats", help}, + {"conn", help}, + {"help", help}, + {"exit", shell_quit}, + {"?", help}, + {NULL, unknown} +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void parse(void *handle, char *str, struct ptentry_s *t) +{ + struct ptentry_s *p; + + for (p = t; p->commandstr != NULL; ++p) + { + if (strncmp(p->commandstr, str, strlen(p->commandstr)) == 0) + { + break; + } + } + + p->pfunc(handle, str); +} + +static void help(void *handle, char *str) +{ + shell_output(handle, "Available commands:"); + shell_output(handle, "stats - show network statistics"); + shell_output(handle, "conn - show TCP connections"); + shell_output(handle, "help, ? - show help"); + shell_output(handle, "exit - exit shell"); +} + +static void unknown(void *handle, char *str) +{ + if (strlen(str) > 0) + { + shell_output(handle, "Unknown command: ", str); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void shell_init(void *handle) +{ +} + +void shell_start(void *handle) +{ + shell_output(handle, "uIP command shell"); + shell_output(handle, "Type '?' and return for help"); + shell_prompt(handle, SHELL_PROMPT); +} + +void shell_input(void *handle, char *cmd) +{ + parse(handle, cmd, g_parsetab); + shell_prompt(handle, SHELL_PROMPT); +} diff --git a/apps/netutils/telnetd/shell.h b/apps/netutils/telnetd/shell.h new file mode 100644 index 000000000..32325fe17 --- /dev/null +++ b/apps/netutils/telnetd/shell.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * netutils/telnetd/shell.h + * Interface for the Contiki shell. + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based on uIP which also has a BSD style license: + * + * Author: Adam Dunkels <adam@dunkels.com> + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* Some of the functions declared in this file must be implemented as + * a shell back-end in the architecture specific files of a Contiki + * port. + */ + +#ifndef __SHELL_H__ +#define __SHELL_H__ + +/* Initialize the shell. + * + * Called when the shell front-end process starts. This function may + * be used to start listening for signals. + */ + +void shell_init(void *handle); + +/* Start the shell back-end. + * + * Called by the front-end when a new shell is started. + */ + +void shell_start(void *handle); + +/* Process a shell command. + * + * This function will be called by the shell GUI / telnet server whan + * a command has been entered that should be processed by the shell + * back-end. + * + * command The command to be processed. + */ + +void shell_input(void *handle, char *command); + +/* Quit the shell. */ + +void shell_quit(void *handle, char *); + +/* Print a string to the shell window. + * + * This function is implemented by the shell GUI / telnet server and + * can be called by the shell back-end to output a string in the + * shell window. The string is automatically appended with a linebreak. + */ + +void shell_output(void *handle, const char *fmt, ...); + +/* Print a prompt to the shell window. + * + * This function can be used by the shell back-end to print out a + * prompt to the shell window. + * + */ + +void shell_prompt(void *handle, char *prompt); + +#endif /* __SHELL_H__ */ diff --git a/apps/netutils/telnetd/telnetd.c b/apps/netutils/telnetd/telnetd.c new file mode 100644 index 000000000..ccadd60dd --- /dev/null +++ b/apps/netutils/telnetd/telnetd.c @@ -0,0 +1,459 @@ +/**************************************************************************** + * netutils/telnetd/telnetd.c + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * This is a leverage of similar logic from uIP: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <pthread.h> +#include <debug.h> + +#include <apps/netutils/telnetd.h> +#include <apps/netutils/uiplib.h> + +#include "shell.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +#define STATE_NORMAL 0 +#define STATE_IAC 1 +#define STATE_WILL 2 +#define STATE_WONT 3 +#define STATE_DO 4 +#define STATE_DONT 5 +#define STATE_CLOSE 6 + +#define TELNET_IAC 255 +#define TELNET_WILL 251 +#define TELNET_WONT 252 +#define TELNET_DO 253 +#define TELNET_DONT 254 + +/* Configurable settings */ + +#ifndef CONFIG_NETUTILS_IOBUFFER_SIZE +# define CONFIG_NETUTILS_IOBUFFER_SIZE 512 +#endif + +#ifndef CONFIG_NETUTILS_CMD_SIZE +# define CONFIG_NETUTILS_CMD_SIZE 40 +#endif + +/* As threads are created to handle each request, a stack must be allocated + * for the thread. Use a default if the user provided no stacksize. + */ + +#ifndef CONFIG_NETUTILS_TELNETDSTACKSIZE +# define CONFIG_NETUTILS_TELNETDSTACKSIZE 4096 +#endif + +/* Enabled dumping of all input/output buffers */ + +#undef CONFIG_NETUTILS_TELNETD_DUMPBUFFER + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct telnetd_s +{ + int tn_sockfd; + char tn_iobuffer[CONFIG_NETUTILS_IOBUFFER_SIZE]; + char tn_cmd[CONFIG_NETUTILS_CMD_SIZE]; + uint8_t tn_bufndx; + uint8_t tn_state; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: telnetd_dumpbuffer + * + * Description: + * Dump a buffer of data (debug only) + * + ****************************************************************************/ + +#ifdef CONFIG_NETUTILS_TELNETD_DUMPBUFFER +static inline void telnetd_dumpbuffer(FAR const char *msg, FAR const char *buffer, unsigned int nbytes) +{ + /* CONFIG_DEBUG, CONFIG_DEBUG_VERBOSE, and CONFIG_DEBUG_NET have to be + * defined or the following does nothing. + */ + + nvdbgdumpbuffer(msg, (FAR const uint8_t*)buffer, nbytes); +} +#else +# define telnetd_dumpbuffer(msg,buffer,nbytes) +#endif + +/**************************************************************************** + * Name: telnetd_putchar + * + * Description: + * Add another parsed character to the TELNET command string + * + ****************************************************************************/ + +static void telnetd_putchar(struct telnetd_s *pstate, uint8_t ch) +{ + /* Ignore carriage returns */ + + if (ch == ISO_cr) + { + return; + } + + /* Add all other characters to the cmd buffer */ + + pstate->tn_cmd[pstate->tn_bufndx] = ch; + + /* If a newline was added or if the buffer is full, then process it now */ + + if (ch == ISO_nl || pstate->tn_bufndx == (CONFIG_NETUTILS_CMD_SIZE - 1)) + { + if (pstate->tn_bufndx > 0) + { + pstate->tn_cmd[pstate->tn_bufndx] = '\0'; + } + + telnetd_dumpbuffer("TELNET CMD", pstate->tn_cmd, strlen(pstate->tn_cmd)); + shell_input(pstate, pstate->tn_cmd); + pstate->tn_bufndx = 0; + } + else + { + pstate->tn_bufndx++; + vdbg("Add '%c', bufndx=%d\n", ch, pstate->tn_bufndx); + } +} + +/**************************************************************************** + * Name: telnetd_sendopt + * + * Description: + * + ****************************************************************************/ + +static void telnetd_sendopt(struct telnetd_s *pstate, uint8_t option, uint8_t value) +{ + uint8_t optbuf[4]; + optbuf[0] = TELNET_IAC; + optbuf[1] = option; + optbuf[2] = value; + optbuf[3] = 0; + + telnetd_dumpbuffer("Send optbuf", optbuf, 4); + if (send(pstate->tn_sockfd, optbuf, 4, 0) < 0) + { + dbg("[%d] Failed to send TELNET_IAC\n", pstate->tn_sockfd); + } +} + +/**************************************************************************** + * Name: telnetd_receive + * + * Description: + * Process a received TELENET buffer + * + ****************************************************************************/ + +static int telnetd_receive(struct telnetd_s *pstate, size_t len) +{ + char *ptr = pstate->tn_iobuffer; + uint8_t ch; + + while (len > 0) + { + ch = *ptr++; + len--; + + vdbg("ch=%02x state=%d\n", ch, pstate->tn_state); + switch (pstate->tn_state) + { + case STATE_IAC: + if (ch == TELNET_IAC) + { + telnetd_putchar(pstate, ch); + pstate->tn_state = STATE_NORMAL; + } + else + { + switch (ch) + { + case TELNET_WILL: + pstate->tn_state = STATE_WILL; + break; + + case TELNET_WONT: + pstate->tn_state = STATE_WONT; + break; + + case TELNET_DO: + pstate->tn_state = STATE_DO; + break; + + case TELNET_DONT: + pstate->tn_state = STATE_DONT; + break; + + default: + pstate->tn_state = STATE_NORMAL; + break; + } + } + break; + + case STATE_WILL: + /* Reply with a DONT */ + + telnetd_sendopt(pstate, TELNET_DONT, ch); + pstate->tn_state = STATE_NORMAL; + break; + + case STATE_WONT: + /* Reply with a DONT */ + + telnetd_sendopt(pstate, TELNET_DONT, ch); + pstate->tn_state = STATE_NORMAL; + break; + + case STATE_DO: + /* Reply with a WONT */ + + telnetd_sendopt(pstate, TELNET_WONT, ch); + pstate->tn_state = STATE_NORMAL; + break; + + case STATE_DONT: + /* Reply with a WONT */ + + telnetd_sendopt(pstate, TELNET_WONT, ch); + pstate->tn_state = STATE_NORMAL; + break; + + case STATE_NORMAL: + if (ch == TELNET_IAC) + { + pstate->tn_state = STATE_IAC; + } + else + { + telnetd_putchar(pstate, ch); + } + break; + } + } + return OK; +} + +/**************************************************************************** + * Name: telnetd_handler + * + * Description: + * Each time a new connection to port 23 is made, a new thread is created + * that begins at this entry point. There should be exactly one argument + * and it should be the socket descriptor (+1). + * + ****************************************************************************/ + +static void *telnetd_handler(void *arg) +{ + struct telnetd_s *pstate = (struct telnetd_s *)malloc(sizeof(struct telnetd_s)); + int sockfd = (int)arg; + int ret = ERROR; + + dbg("[%d] Started\n", sockfd); + + /* Verify that the state structure was successfully allocated */ + + if (pstate) + { + /* Initialize the thread state structure */ + + memset(pstate, 0, sizeof(struct telnetd_s)); + pstate->tn_sockfd = sockfd; + pstate->tn_state = STATE_NORMAL; + + /* Start up the shell */ + + shell_init(pstate); + shell_start(pstate); + + /* Loop processing each TELNET command */ + do + { + /* Read a buffer of data from the TELNET client */ + + ret = recv(pstate->tn_sockfd, pstate->tn_iobuffer, CONFIG_NETUTILS_IOBUFFER_SIZE, 0); + if (ret > 0) + { + + /* Process the received TELNET data */ + + telnetd_dumpbuffer("Received buffer", pstate->tn_iobuffer, ret); + ret = telnetd_receive(pstate, ret); + } + } + while (ret >= 0 && pstate->tn_state != STATE_CLOSE); + dbg("[%d] ret=%d tn_state=%d\n", sockfd, ret, pstate->tn_state); + + /* End of command processing -- Clean up and exit */ + + free(pstate); + } + + /* Exit the task */ + + dbg("[%d] Exitting\n", sockfd); + close(sockfd); + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: telnetd_init + * + * Description: + * This is the main processing thread for telnetd. It never returns + * unless an error occurs + * + ****************************************************************************/ + +void telnetd_init(void) +{ + /* Execute telnetd_handler on each connection to port 23 */ + + uip_server(HTONS(23), telnetd_handler, CONFIG_NETUTILS_TELNETDSTACKSIZE); +} + +/**************************************************************************** + * Name: shell_prompt + * + * Description: + * Print a prompt to the shell window. + * + * This function can be used by the shell back-end to print out a prompt + * to the shell window. + * + ****************************************************************************/ + +void shell_prompt(void *handle, char *str) +{ + struct telnetd_s *pstate = (struct telnetd_s *)handle; + int len = strlen(str); + + strncpy(pstate->tn_iobuffer, str, len); + telnetd_dumpbuffer("Shell prompt", pstate->tn_iobuffer, len); + if (send(pstate->tn_sockfd, pstate->tn_iobuffer, len, 0) < 0) + { + dbg("[%d] Failed to send prompt\n", pstate->tn_sockfd); + } +} + +/**************************************************************************** + * Name: shell_output + * + * Description: + * Print a string to the shell window. + * + * This function is implemented by the shell GUI / telnet server and + * can be called by the shell back-end to output a string in the + * shell window. The string is automatically appended with a linebreak. + * + ****************************************************************************/ + +void shell_output(void *handle, const char *fmt, ...) +{ + struct telnetd_s *pstate = (struct telnetd_s *)handle; + unsigned len; + va_list ap; + + va_start(ap, fmt); + vsnprintf(pstate->tn_iobuffer, CONFIG_NETUTILS_IOBUFFER_SIZE, fmt, ap); + va_end(ap); + + len = strlen(pstate->tn_iobuffer); + if (len < CONFIG_NETUTILS_IOBUFFER_SIZE - 2) + { + pstate->tn_iobuffer[len] = ISO_cr; + pstate->tn_iobuffer[len+1] = ISO_nl; + pstate->tn_iobuffer[len+2] = '\0'; + } + + telnetd_dumpbuffer("Shell output", pstate->tn_iobuffer, len+2); + if (send(pstate->tn_sockfd, pstate->tn_iobuffer, len+2, 0) < 0) + { + dbg("[%d] Failed to send response\n", pstate->tn_sockfd); + } +} + +/**************************************************************************** + * Name: shell_quit + * + * Description: + * Quit the shell + * + ****************************************************************************/ + +void shell_quit(void *handle, char *str) +{ + struct telnetd_s *pstate = (struct telnetd_s *)handle; + pstate->tn_state = STATE_CLOSE; +} + diff --git a/apps/netutils/tftpc/Makefile b/apps/netutils/tftpc/Makefile new file mode 100644 index 000000000..1ec7b2b90 --- /dev/null +++ b/apps/netutils/tftpc/Makefile @@ -0,0 +1,99 @@ +############################################################################ +# apps/netutils/tftpc/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# TFTP Client Library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_UDP),y) +ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) +CSRCS += tftpc_get.c tftpc_put.c tftpc_packets.c +endif +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/tftpc/tftpc_get.c b/apps/netutils/tftpc/tftpc_get.c new file mode 100644 index 000000000..bfae1a3b7 --- /dev/null +++ b/apps/netutils/tftpc/tftpc_get.c @@ -0,0 +1,337 @@ +/**************************************************************************** + * netuils/tftp/tftpc_get.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, TFTP_DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include <net/uip/uipopt.h> +#include <net/uip/uip.h> +#include <apps/netutils/tftp.h> + +#include "tftpc_internal.h" + +#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define TFTP_RETRIES 3 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tftp_write + ****************************************************************************/ + +static inline ssize_t tftp_write(int fd, const uint8_t *buf, size_t len) +{ + size_t left = len; + ssize_t nbyteswritten; + + while (left > 0) + { + /* Write the data... repeating the write in the event that it was + * interrupted by a signal. + */ + + do + { + nbyteswritten = write(fd, buf, left); + } + while (nbyteswritten < 0 && errno == EINTR); + + /* Check for non-EINTR errors */ + + if (nbyteswritten < 0) + { + ndbg("write failed: %d\n", errno); + return ERROR; + } + + /* Handle partial writes */ + + nvdbg("Wrote %d bytes to file\n", nbyteswritten); + left -= nbyteswritten; + buf += nbyteswritten; + } + return len; +} + +/**************************************************************************** + * Name: tftp_parsedatapacket + ****************************************************************************/ + +static inline int tftp_parsedatapacket(const uint8_t *packet, + uint16_t *opcode, uint16_t *blockno) +{ + *opcode = (uint16_t)packet[0] << 8 | (uint16_t)packet[1]; + if (*opcode == TFTP_DATA) + { + *blockno = (uint16_t)packet[2] << 8 | (uint16_t)packet[3]; + return OK; + } +#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET) + else if (*opcode == TFTP_ERR) + { + (void)tftp_parseerrpacket(packet); + } +#endif + return ERROR; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tftpget + * + * Input Parameters: + * remote - The name of the file on the TFTP server. + * local - Path to the location on a mounted filesystem where the file + * will be stored. + * addr - The IP address of the server in network order + * binary - TRUE: Perform binary ('octect') transfer + * FALSE: Perform text ('netascii') transfer + * + ****************************************************************************/ + +int tftpget(const char *remote, const char *local, in_addr_t addr, bool binary) +{ + struct sockaddr_in server; /* The address of the TFTP server */ + struct sockaddr_in from; /* The address the last UDP message recv'd from */ + uint8_t *packet; /* Allocated memory to hold one packet */ + uint16_t blockno = 0; /* The current transfer block number */ + uint16_t opcode; /* Received opcode */ + uint16_t rblockno; /* Received block number */ + int len; /* Generic length */ + int sd; /* Socket descriptor for socket I/O */ + int fd; /* File descriptor for file I/O */ + int retry; /* Retry counter */ + int nbytesrecvd = 0; /* The number of bytes received in the packet */ + int ndatabytes; /* The number of data bytes received */ + int result = ERROR; /* Assume failure */ + int ret; /* Generic return status */ + + /* Allocate the buffer to used for socket/disk I/O */ + + packet = (uint8_t*)zalloc(TFTP_IOBUFSIZE); + if (!packet) + { + ndbg("packet memory allocation failure\n"); + set_errno(ENOMEM); + goto errout; + } + + /* Open the file for writing */ + + fd = open(local, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd < 0) + { + ndbg("open failed: %d\n", errno); + goto errout_with_packet; + } + + /* Initialize a UDP socket and setup the server addresss */ + + sd = tftp_sockinit(&server, addr); + if (sd < 0) + { + goto errout_with_fd; + } + + /* Then enter the transfer loop. Loop until the entire file has + * been received or until an error occurs. + */ + + do + { + /* Increment the TFTP block number for the next transfer */ + + blockno++; + + /* Send the next block if the file within a loop. We will + * retry up to TFTP_RETRIES times before giving up on the + * transfer. + */ + + for (retry = 0; retry < TFTP_RETRIES; retry++) + { + /* Send the read request using the well-known port number before + * receiving the first block. Each retry of the first block will + * re-send the request. + */ + + if (blockno == 1) + { + len = tftp_mkreqpacket(packet, TFTP_RRQ, remote, binary); + server.sin_port = HTONS(CONFIG_NETUTILS_TFTP_PORT); + ret = tftp_sendto(sd, packet, len, &server); + if (ret != len) + { + goto errout_with_sd; + } + + /* Subsequent sendto will use the port number selected by the TFTP + * server in the DATA packet. Setting the server port to zero + * here indicates that we have not yet received the server port number. + */ + + server.sin_port = 0; + } + + /* Get the next packet from the server */ + + nbytesrecvd = tftp_recvfrom(sd, packet, TFTP_IOBUFSIZE, &from); + + /* Check if anything valid was received */ + + if (nbytesrecvd >= 0) + { + /* Verify the sender address and port number */ + + if (server.sin_addr.s_addr != from.sin_addr.s_addr) + { + nvdbg("Invalid address in DATA\n"); + retry--; + continue; + } + + if (server.sin_port && server.sin_port != from.sin_port) + { + nvdbg("Invalid port in DATA\n"); + len = tftp_mkerrpacket(packet, TFTP_ERR_UNKID, TFTP_ERRST_UNKID); + ret = tftp_sendto(sd, packet, len, &from); + retry--; + continue; + } + + /* Parse the incoming DATA packet */ + + if (nbytesrecvd < TFTP_DATAHEADERSIZE) + { + /* Packet is not big enough to be parsed */ + + nvdbg("Tiny data packet ignored\n"); + continue; + } + + if (tftp_parsedatapacket(packet, &opcode, &rblockno) != OK || + blockno != rblockno) + { + /* Opcode is not TFTP_DATA or the block number is unexpected */ + + nvdbg("Parse failure\n"); + if (opcode > TFTP_MAXRFC1350) + { + len = tftp_mkerrpacket(packet, TFTP_ERR_ILLEGALOP, TFTP_ERRST_ILLEGALOP); + ret = tftp_sendto(sd, packet, len, &from); + } + continue; + } + + /* Replace the server port to the one in the good data response */ + + if (!server.sin_port) + { + server.sin_port = from.sin_port; + } + + /* Then break out of the loop */ + + break; + } + } + + /* Did we exhaust all of the retries? */ + + if (retry == TFTP_RETRIES) + { + nvdbg("Retry limit exceeded\n"); + goto errout_with_sd; + } + + /* Write the received data chunk to the file */ + + ndatabytes = nbytesrecvd - TFTP_DATAHEADERSIZE; + tftp_dumpbuffer("Recvd DATA", packet + TFTP_DATAHEADERSIZE, ndatabytes); + if (tftp_write(fd, packet + TFTP_DATAHEADERSIZE, ndatabytes) < 0) + { + goto errout_with_sd; + } + + /* Send the acknowledgment */ + + len = tftp_mkackpacket(packet, blockno); + ret = tftp_sendto(sd, packet, len, &server); + if (ret != len) + { + goto errout_with_sd; + } + nvdbg("ACK blockno %d\n", blockno); + } + while (ndatabytes >= TFTP_DATASIZE); + + /* Return success */ + + result = OK; + +errout_with_sd: + close(sd); +errout_with_fd: + close(fd); +errout_with_packet: + free(packet); +errout: + return result; +} + +#endif /* CONFIG_NET && CONFIG_NET_UDP && CONFIG_NFILE_DESCRIPTORS > 0 */ diff --git a/apps/netutils/tftpc/tftpc_internal.h b/apps/netutils/tftpc/tftpc_internal.h new file mode 100644 index 000000000..ffaecdb13 --- /dev/null +++ b/apps/netutils/tftpc/tftpc_internal.h @@ -0,0 +1,173 @@ +/**************************************************************************** + * netutils/tftoc/tftpc_internal.h + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NETUTILS_TFTP_TFTPC_INTERNAL_H +#define __NETUTILS_TFTP_TFTPC_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/compiler.h> + +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> + +#include <net/uip/uipopt.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Verify TFTP configuration settings ***************************************/ +/* The settings beginning with CONFIG_NETUTILS_TFTP_* can all be set in the + * NuttX configuration file. If they are are defined in the configuration + * then default values are assigned here. + */ + +/* The "well-known" server TFTP port number (usually 69). This port number + * is only used for the initial server contact. The server will negotiate + * a new transfer port number after the initial client request. + */ + +#ifndef CONFIG_NETUTILS_TFTP_PORT +# define CONFIG_NETUTILS_TFTP_PORT 69 +#endif + +/* recvfrom timeout in deci-seconds */ + +#ifndef CONFIG_NETUTILS_TFTP_TIMEOUT +# define CONFIG_NETUTILS_TFTP_TIMEOUT 10 /* One second */ +#endif + +/* Dump received buffers */ + +#undef CONFIG_NETUTILS_TFTP_DUMPBUFFERS + +/* Sizes of TFTP messsage headers */ + +#define TFTP_ACKHEADERSIZE 4 +#define TFTP_ERRHEADERSIZE 4 +#define TFTP_DATAHEADERSIZE 4 + +/* The maximum size for TFTP data is determined by the configured uIP packet + * size (but cannot exceed 512 + sizeof(TFTP_DATA header). + */ + +#define TFTP_DATAHEADERSIZE 4 +#define TFTP_MAXPACKETSIZE (TFTP_DATAHEADERSIZE+512) + +#if UIP_UDP_MSS < TFTP_MAXPACKETSIZE +# define TFTP_PACKETSIZE UIP_UDP_MSS +# ifdef CONFIG_CPP_HAVE_WARNING +# warning "uIP MSS is too small for TFTP" +# endif +#else +# define TFTP_PACKETSIZE TFTP_MAXPACKETSIZE +#endif + +#define TFTP_DATASIZE (TFTP_PACKETSIZE-TFTP_DATAHEADERSIZE) +#define TFTP_IOBUFSIZE (TFTP_PACKETSIZE+8) + +/* TFTP Opcodes *************************************************************/ + +#define TFTP_RRQ 1 /* Read Request RFC 1350, RFC 2090 */ +#define TFTP_WRQ 2 /* Write Request RFC 1350 */ +#define TFTP_DATA 3 /* Data chunk RFC 1350 */ +#define TFTP_ACK 4 /* Acknowledgement RFC 1350 */ +#define TFTP_ERR 5 /* Error Message RFC 1350 */ +#define TFTP_OACK 6 /* Option acknowledgment RFC 2347 */ + +#define TFTP_MAXRFC1350 5 + +/* TFTP Error Codes *********************************************************/ + +/* Error codes */ + +#define TFTP_ERR_NONE 0 /* No error */ +#define TFTP_ERR_NOSUCHFILE 1 /* File not found */ +#define TFTP_ERR_ACCESS 2 /* Access violation */ +#define TFTP_ERR_FULL 3 /* Disk full or allocation exceeded */ +#define TFTP_ERR_ILLEGALOP 4 /* Illegal TFTP operation */ +#define TFTP_ERR_UNKID 5 /* Unknown transfer ID */ +#define TFTP_ERR_EXISTS 6 /* File already exists */ +#define TFTP_ERR_UNKUSER 7 /* No such user */ +#define TFTP_ERR_NEGOTIATE 8 /* Terminate transfer due to option negotiation */ + +/* Error strings */ + +#define TFTP_ERR_STNOSUCHFILE "File not found" +#define TFTP_ERRST_ACCESS "Access violation" +#define TFTP_ERRST_FULL "Disk full or allocation exceeded" +#define TFTP_ERRST_ILLEGALOP "Illegal TFTP operation" +#define TFTP_ERRST_UNKID "Unknown transfer ID" +#define TFTP_ERRST_EXISTS "File already exists" +#define TFTP_ERRST_UNKUSER "No such user" +#define TFTP_ERRST_NEGOTIATE "Terminate transfer due to option negotiation" + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Defined in tftp_packet.c *************************************************/ + +extern int tftp_sockinit(struct sockaddr_in *server, in_addr_t addr); +extern int tftp_mkreqpacket(uint8_t *buffer, int opcode, const char *path, bool binary); +extern int tftp_mkackpacket(uint8_t *buffer, uint16_t blockno); +extern int tftp_mkerrpacket(uint8_t *buffer, uint16_t errorcode, const char *errormsg); +#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET) +extern int tftp_parseerrpacket(const uint8_t *packet); +#endif + +extern ssize_t tftp_recvfrom(int sd, void *buf, size_t len, struct sockaddr_in *from); +extern ssize_t tftp_sendto(int sd, const void *buf, size_t len, struct sockaddr_in *to); + +#ifdef CONFIG_NETUTILS_TFTP_DUMPBUFFERS +# define tftp_dumpbuffer(msg, buffer, nbytes) nvdbgdumpbuffer(msg, buffer, nbytes) +#else +# define tftp_dumpbuffer(msg, buffer, nbytes) +#endif + +#endif /* __NETUTILS_TFTP_TFTPC_INTERNAL_H */ diff --git a/apps/netutils/tftpc/tftpc_packets.c b/apps/netutils/tftpc/tftpc_packets.c new file mode 100644 index 000000000..d43410ff4 --- /dev/null +++ b/apps/netutils/tftpc/tftpc_packets.c @@ -0,0 +1,330 @@ +/**************************************************************************** + * netuils/tftp/tftpc_packets.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, TFTP_DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <debug.h> + +#include <netinet/in.h> + +#include <net/uip/uipopt.h> +#include <net/uip/uip.h> +#include <apps/netutils/tftp.h> + +#include "tftpc_internal.h" + +#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tftp_mode + ****************************************************************************/ + +static inline const char *tftp_mode(bool binary) +{ + return binary ? "octet" : "netascii"; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tftp_sockinit + * + * Description: + * Common initialization logic: Create the socket and initialize the + * server address structure. + * + ****************************************************************************/ + +int tftp_sockinit(struct sockaddr_in *server, in_addr_t addr) +{ + struct timeval timeo; + int sd; + int ret; + + /* Create the UDP socket */ + + sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sd < 0) + { + ndbg("socket failed: %d\n", errno); + return ERROR; + } + + /* Set the recvfrom timeout */ + + timeo.tv_sec = CONFIG_NETUTILS_TFTP_TIMEOUT / 10; + timeo.tv_usec = (CONFIG_NETUTILS_TFTP_TIMEOUT % 10) * 100000; + ret = setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(struct timeval)); + if (ret < 0) + { + ndbg("setsockopt failed: %d\n", errno); + } + + /* Initialize the server address structure */ + + memset(server, 0, sizeof(struct sockaddr_in)); + server->sin_family = AF_INET; + server->sin_addr.s_addr = addr; + server->sin_port = HTONS(CONFIG_NETUTILS_TFTP_PORT); + return sd; +} + +/**************************************************************************** + * Name: tftp_mkreqpacket + * + * Description: + * RRQ or WRQ message format: + * + * 2 bytes: Opcode (network order == big-endian) + * N bytes: Filename + * 1 byte: 0 + * N bytes: mode + * 1 byte: 0 + * + * Return + * Then number of bytes in the request packet (never fails) + * + ****************************************************************************/ + +int tftp_mkreqpacket(uint8_t *buffer, int opcode, const char *path, bool binary) +{ + buffer[0] = opcode >> 8; + buffer[1] = opcode & 0xff; + return sprintf((char*)&buffer[2], "%s%c%s", path, 0, tftp_mode(binary)) + 3; +} + +/**************************************************************************** + * Name: tftp_mkackpacket + * + * Description: + * ACK message format: + * + * 2 bytes: Opcode (network order == big-endian) + * 2 bytes: Block number (network order == big-endian) + * + ****************************************************************************/ + +int tftp_mkackpacket(uint8_t *buffer, uint16_t blockno) +{ + buffer[0] = TFTP_ACK >> 8; + buffer[1] = TFTP_ACK & 0xff; + buffer[2] = blockno >> 8; + buffer[3] = blockno & 0xff; + return 4; +} + +/**************************************************************************** + * Name: tftp_mkerrpacket + * + * Description: + * ERROR message format: + * + * 2 bytes: Opcode (network order == big-endian) + * 2 bytes: Error number (network order == big-endian) + * N bytes: Error string + * 1 byte: 0 + * + ****************************************************************************/ + +int tftp_mkerrpacket(uint8_t *buffer, uint16_t errorcode, const char *errormsg) +{ + buffer[0] = TFTP_ERR >> 8; + buffer[1] = TFTP_ERR & 0xff; + buffer[2] = errorcode >> 8; + buffer[3] = errorcode & 0xff; + strcpy((char*)&buffer[4], errormsg); + return strlen(errormsg) + 5; +} + +/**************************************************************************** + * Name: tftp_parseerrpacket + * + * Description: + * ERROR message format: + * + * 2 bytes: Opcode (network order == big-endian) + * 2 bytes: Error number (network order == big-endian) + * N bytes: Error string + * 1 byte: 0 + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET) +int tftp_parseerrpacket(const uint8_t *buffer) +{ + uint16_t opcode = (uint16_t)buffer[0] << 8 | (uint16_t)buffer[1]; + uint16_t errcode = (uint16_t)buffer[2] << 8 | (uint16_t)buffer[3]; + const char *errmsg = (const char *)&buffer[4]; + + if (opcode == TFTP_ERR) + { + ndbg("ERR message: %s (%d)\n", errmsg, errcode); + return OK; + } + return ERROR; +} +#endif + +/**************************************************************************** + * Name: tftp_recvfrom + * + * Description: + * recvfrom helper + * + ****************************************************************************/ + +ssize_t tftp_recvfrom(int sd, void *buf, size_t len, struct sockaddr_in *from) +{ + int addrlen; + ssize_t nbytes; + + /* Loop handles the case where the recvfrom is interrupted by a signal and + * we should unconditionally try again. + */ + + for (;;) + { + /* For debugging, it is helpful to start with a clean buffer */ + +#if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_NET) + memset(buf, 0, len); +#endif + + /* Receive the packet */ + + addrlen = sizeof(struct sockaddr_in); + nbytes = recvfrom(sd, buf, len, 0, (struct sockaddr*)from, (socklen_t*)&addrlen); + + /* Check for errors */ + + if (nbytes < 0) + { + /* Check for a timeout */ + + if (errno == EAGAIN) + { + ndbg("recvfrom timed out\n"); + return ERROR; + } + + /* If EINTR, then loop and try again. Other errors are fatal */ + + else if (errno != EINTR) + { + ndbg("recvfrom failed: %d\n", errno); + return ERROR; + } + } + + /* No errors? Return the number of bytes received */ + + else + { + return nbytes; + } + } +} + +/**************************************************************************** + * Name: tftp_sendto + * + * Description: + * sendto helper + * + ****************************************************************************/ + +ssize_t tftp_sendto(int sd, const void *buf, size_t len, struct sockaddr_in *to) +{ + ssize_t nbytes; + + /* Loop handles the case where the sendto is interrupted by a signal and + * we should unconditionally try again. + */ + + for (;;) + { + /* Send the packet */ + + nbytes = sendto(sd, buf, len, 0, (struct sockaddr*)to, sizeof(struct sockaddr_in)); + + /* Check for errors */ + + if (nbytes < 0) + { + /* If EINTR, then loop and try again. Other errors are fatal */ + + if (errno != EINTR) + { + ndbg("sendto failed: %d\n", errno); + return ERROR; + } + } + + /* No errors? Return the number of bytes received */ + + else + { + return nbytes; + } + } +} + +#endif /* CONFIG_NET && CONFIG_NET_UDP && CONFIG_NFILE_DESCRIPTORS */ diff --git a/apps/netutils/tftpc/tftpc_put.c b/apps/netutils/tftpc/tftpc_put.c new file mode 100644 index 000000000..c292244a6 --- /dev/null +++ b/apps/netutils/tftpc/tftpc_put.c @@ -0,0 +1,477 @@ +/**************************************************************************** + * netuils/tftp/tftpc_put.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, TFTP_DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include <net/uip/uipopt.h> +#include <net/uip/uip.h> +#include <apps/netutils/tftp.h> + +#include "tftpc_internal.h" + +#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define TFTP_RETRIES 3 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tftp_read + ****************************************************************************/ + +static inline ssize_t tftp_read(int fd, uint8_t *buf, size_t buflen) +{ + ssize_t nbytesread; + ssize_t totalread = 0; + + while (totalread < buflen) + { + /* Read the data... repeating the read in the event that it was + * interrupted by a signal. + */ + + do + { + nbytesread = read(fd, buf, buflen - totalread); + } + while (nbytesread < 0 && errno == EINTR); + + /* Check for non-EINTR errors */ + + if (nbytesread < 0) + { + ndbg("read failed: %d\n", errno); + return ERROR; + } + + /* Check for end of file */ + + else if (nbytesread == 0) + { + break; + } + + /* Handle partial reads. Partial reads can happen normally + * when the source is some device driver that returns data + * in bits and pieces as received (such as a pipe) + */ + + totalread += nbytesread; + buf += nbytesread; + } + return totalread; +} + +/**************************************************************************** + * Name: tftp_mkdatapacket + * + * Description: + * DATA message format: + * + * 2 bytes: Opcode (network order == big-endian) + * 2 bytes: Block number (network order == big-endian) + * N bytes: Data (where N <= 512) + * + * Input Parameters: + * fd - File descriptor used to read from the file + * offset - File offset to read from + * packet - Buffer to write the data packet into + * blockno - The block number of the packet + * + * Return Value: + * Number of bytes read into the packet. <TFTP_PACKETSIZE means end of file; + * <1 if an error occurs. + * + ****************************************************************************/ + +int tftp_mkdatapacket(int fd, off_t offset, uint8_t *packet, uint16_t blockno) +{ + off_t tmp; + int nbytesread; + + /* Format the DATA message header */ + + packet[0] = TFTP_DATA >> 8; + packet[1] = TFTP_DATA & 0xff; + packet[2] = blockno >> 8; + packet[3] = blockno & 0xff; + + /* Seek to the correct offset in the file */ + + tmp = lseek(fd, offset, SEEK_SET); + if (tmp == (off_t)-1) + { + ndbg("lseek failed: %d\n", errno); + return ERROR; + } + + /* Read the file data into the packet buffer */ + + nbytesread = tftp_read(fd, &packet[TFTP_DATAHEADERSIZE], TFTP_DATASIZE); + if (nbytesread < 0) + { + return ERROR; + } + return nbytesread + TFTP_DATAHEADERSIZE; +} + +/**************************************************************************** + * Name: tftp_rcvack + * + * Description: + * ACK message format: + * + * 2 bytes: Opcode (network order == big-endian) + * 2 bytes: Block number (network order == big-endian) + * + * Input Parameters: + * sd - Socket descriptor to use in in the transfer + * packet - buffer to use for the tranfers + * server - The address of the server + * port - The port number of the server (0 if not yet known) + * blockno - Location to return block number in the received ACK + * + * Returned Value: + * OK:success and blockno valid, ERROR:failure. + * + ****************************************************************************/ + +static int tftp_rcvack(int sd, uint8_t *packet, struct sockaddr_in *server, + uint16_t *port, uint16_t *blockno) +{ + struct sockaddr_in from; /* The address the last UDP message recv'd from */ + ssize_t nbytes; /* The number of bytes received. */ + uint16_t opcode; /* The received opcode */ + uint16_t rblockno; /* The received block number */ + int packetlen; /* Packet length */ + int retry; /* Retry counter */ + + /* Try up to TFTP_RETRIES times */ + + for (retry = 0; retry < TFTP_RETRIES; retry++) + { + /* Try for until a valid ACK is received or some error occurs */ + + for (;;) + { + /* Receive the next UDP packet from the server */ + + nbytes = tftp_recvfrom(sd, packet, TFTP_IOBUFSIZE, &from); + if (nbytes < TFTP_ACKHEADERSIZE) + { + /* Failed to receive a good packet */ + + if (nbytes >= 0) + { + ndbg("tftp_recvfrom short packet: %d bytes\n", nbytes); + } + + /* Break out to bump up the retry count */ + + break; + } + else + { + /* Get the port being used by the server if that has not yet been established */ + + if (!*port) + { + *port = from.sin_port; + server->sin_port = from.sin_port; + } + + /* Verify that the packet was received from the correct host and port */ + + if (server->sin_addr.s_addr != from.sin_addr.s_addr) + { + nvdbg("Invalid address in DATA\n"); + continue; + } + + if (*port != server->sin_port) + { + nvdbg("Invalid port in DATA\n"); + packetlen = tftp_mkerrpacket(packet, TFTP_ERR_UNKID, TFTP_ERRST_UNKID); + (void)tftp_sendto(sd, packet, packetlen, server); + continue; + } + + /* Parse the error message */ + + opcode = (uint16_t)packet[0] << 8 | (uint16_t)packet[1]; + rblockno = (uint16_t)packet[2] << 8 | (uint16_t)packet[3]; + + /* Verify that the message that we received is an ACK for the + * expected block number. + */ + + if (opcode != TFTP_ACK) + { + nvdbg("Bad opcode\n"); +#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET) + if (opcode == TFTP_ERR) + { + (void)tftp_parseerrpacket(packet); + } + else +#endif + if (opcode > TFTP_MAXRFC1350) + { + packetlen = tftp_mkerrpacket(packet, TFTP_ERR_ILLEGALOP, TFTP_ERRST_ILLEGALOP); + (void)tftp_sendto(sd, packet, packetlen, server); + } + + /* Break out an bump up the retry count */ + + break; + } + + /* Success! */ + + nvdbg("Received ACK for block %d\n", rblockno); + *blockno = rblockno; + return OK; + } + } + } + + /* We have tried TFTP_RETRIES times */ + + ndbg("Timeout, Waiting for ACK\n"); + return ERROR; /* Will never get here */ +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tftpput + * + * Input Parameters: + * local - Path to the file system object to be sent. + * remote - The name of the file on the TFTP server. + * addr - The IP address of the server in network order + * binary - TRUE: Perform binary ('octect') transfer + * FALSE: Perform text ('netascii') transfer + * + ****************************************************************************/ + +int tftpput(const char *local, const char *remote, in_addr_t addr, bool binary) +{ + struct sockaddr_in server; /* The address of the TFTP server */ + uint8_t *packet; /* Allocated memory to hold one packet */ + off_t offset; /* Offset into source file */ + uint16_t blockno; /* The current transfer block number */ + uint16_t rblockno; /* The ACK'ed block number */ + uint16_t port = 0; /* This is the port number for the transfer */ + int packetlen; /* The length of the data packet */ + int sd; /* Socket descriptor for socket I/O */ + int fd; /* File descriptor for file I/O */ + int retry; /* Retry counter */ + int result = ERROR; /* Assume failure */ + int ret; /* Generic return status */ + + /* Allocate the buffer to used for socket/disk I/O */ + + packet = (uint8_t*)zalloc(TFTP_IOBUFSIZE); + if (!packet) + { + ndbg("packet memory allocation failure\n"); + set_errno(ENOMEM); + goto errout; + } + + /* Open the file for reading */ + + fd = open(local, O_RDONLY); + if (fd < 0) + { + ndbg("open failed: %d\n", errno); + goto errout_with_packet; + } + + /* Initialize a UDP socket and setup the server addresss */ + + sd = tftp_sockinit(&server, addr); + if (sd < 0) + { + goto errout_with_fd; + } + + /* Send the write request using the well known port. This may need + * to be done several times because (1) UDP is inherenly unreliable + * and packets may be lost normally, and (2) uIP has a nasty habit + * of droppying packets if there is nothing hit in the ARP table. + */ + + blockno = 1; + retry = 0; + for (;;) + { + packetlen = tftp_mkreqpacket(packet, TFTP_WRQ, remote, binary); + ret = tftp_sendto(sd, packet, packetlen, &server); + if (ret != packetlen) + { + goto errout_with_sd; + } + + /* Receive the ACK for the write request */ + + if (tftp_rcvack(sd, packet, &server, &port, NULL) == 0) + { + break; + } + + ndbg("Re-sending request\n"); + + /* We are going to loop and re-send the request packet. Check the + * retry count so that we do not loop forever. + */ + + if (++retry > TFTP_RETRIES) + { + ndbg("Retry count exceeded\n"); + set_errno(ETIMEDOUT); + goto errout_with_sd; + } + } + + /* Then loop sending the entire file to the server in chunks */ + + offset = 0; + retry = 0; + + for (;;) + { + /* Construct the next data packet */ + + packetlen = tftp_mkdatapacket(fd, offset, packet, blockno); + if (packetlen < 0) + { + goto errout_with_sd; + } + + /* Send the next data chunk */ + + ret = tftp_sendto(sd, packet, packetlen, &server); + if (ret != packetlen) + { + goto errout_with_sd; + } + + /* Check for an ACK for the data chunk */ + + if (tftp_rcvack(sd, packet, &server, &port, &rblockno) == OK) + { + /* Check if the packet that we just sent was ACK'ed. If not, + * we just loop to resend the same packet (same blockno, same + * file offset). + */ + + if (rblockno == blockno) + { + /* Yes.. If we are at the end of the file and if all of the packets + * have been ACKed, then we are done. + */ + + if (packetlen < TFTP_PACKETSIZE) + { + break; + } + + /* Not the last block.. set up for the next block */ + + blockno++; + offset += TFTP_DATASIZE; + retry = 0; + + /* Skip the retry test */ + + continue; + } + } + + /* We are going to loop and re-send the data packet. Check the retry + * count so that we do not loop forever. + */ + + if (++retry > TFTP_RETRIES) + { + ndbg("Retry count exceeded\n"); + set_errno(ETIMEDOUT); + goto errout_with_sd; + } + } + + /* Return success */ + + result = OK; + +errout_with_sd: + close(sd); +errout_with_fd: + close(fd); +errout_with_packet: + free(packet); +errout: + return result; +} + +#endif /* CONFIG_NET && CONFIG_NET_UDP && CONFIG_NFILE_DESCRIPTORS > 0 */ diff --git a/apps/netutils/thttpd/Makefile b/apps/netutils/thttpd/Makefile new file mode 100644 index 000000000..4978c7c79 --- /dev/null +++ b/apps/netutils/thttpd/Makefile @@ -0,0 +1,129 @@ +############################################################################# +# apps/netutils/thttpd/Makefile +# +# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################# + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# THTTPD Library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_TCP),y) +CSRCS += thttpd.c libhttpd.c thttpd_cgi.c thttpd_alloc.c thttpd_strings.c timers.c fdwatch.c tdate_parse.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# CGI binaries (examples only, not used in the build) + +CGIBINDIR = $(APPDIR)/netutils/thttpd/cgi-bin + +SUBDIRS = +ifeq ($(CONFIG_NXFLAT),y) +SUBDIRS = cgi-src +SUBDIR_BIN1 = phf +SUBDIR_BIN2 = redirect +SUBDIR_BIN3 = ssi +SUBDIR_BIN += cgi-bin/$(SUBDIR_BIN1) cgi-bin/$(SUBDIR_BIN2) cgi-bin/$(SUBDIR_BIN3) +endif + +all: $(SUBDIR_BIN) .built +.PHONY: depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +ifeq ($(CONFIG_NXFLAT),y) +cgi-bin: + @mkdir cgi-bin + +cgi-src/$(SUBDIR_BIN1): + @$(MAKE) -C cgi-src $(SUBDIR_BIN1) + +cgi-bin/$(SUBDIR_BIN1): cgi-bin cgi-src/$(SUBDIR_BIN1) + @cp -a cgi-src/$(SUBDIR_BIN1) $@ + +cgi-src/$(SUBDIR_BIN2): + @$(MAKE) -C cgi-src $(SUBDIR_BIN2) + +cgi-bin/$(SUBDIR_BIN2): cgi-bin cgi-src/$(SUBDIR_BIN2) + @cp -a cgi-src/$(SUBDIR_BIN2) $@ + +cgi-src/$(SUBDIR_BIN3): + @$(MAKE) -C cgi-src $(SUBDIR_BIN3) + +cgi-bin/$(SUBDIR_BIN3): cgi-bin cgi-src/$(SUBDIR_BIN3) + @cp -a cgi-src/$(SUBDIR_BIN3) $@ +endif + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/thttpd/cgi-src/Makefile b/apps/netutils/thttpd/cgi-src/Makefile new file mode 100644 index 000000000..46b41fd62 --- /dev/null +++ b/apps/netutils/thttpd/cgi-src/Makefile @@ -0,0 +1,140 @@ +############################################################################ +# apps/netutils/cgi-src/Makefile +# +# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" "$(APPDIR)/netutils/thttpd" "$(APPDIR)/netutils/thttpd/cgi-src"} +CGIBINDIR = $(APPDIR)/netutils/thttpd/cgi-bin +CLEANFILES = *.o redirect ssi phf + +BIN1 = phf +BIN2 = redirect +BIN3 = ssi +BIN = $(BIN1) $(BIN2) $(BIN3) + +R1SRCS1 = $(BIN1).c +R1OBJS1 = $(R1SRCS1:.c=.o) +R2SRC1 = $(BIN1)-thunk.S +R2OBJ1 = $(R2SRC1:.S=.o) + +R1SRCS2 = $(BIN2).c +R1OBJS2 = $(R1SRCS2:.c=.o) +R2SRC2 = $(BIN2)-thunk.S +R2OBJ2 = $(R2SRC2:.S=.o) + +R1SRCS3 = $(BIN3).c +R1OBJS3 = $(R1SRCS3:.c=.o) +R2SRC3 = $(BIN3)-thunk.S +R2OBJ3 = $(R2SRC3:.S=.o) + +DERIVED = $(R2SRC1) $(R2SRC2) $(R2SRC3) + +R1COBJS = $(R1OBJS1) $(R1OBJS2) $(R1OBJS3) +R2AOBJS = $(R2OBJ1) $(R2OBJ2) $(R2OBJ3) + +all: $(BIN1) $(BIN2) $(BIN3) + +$(R1COBJS): %.o: %.c + @echo "CC: $<" + $(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2AOBJS): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +# BIN1 + +$(BIN1).r1: $(R1OBJS1) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC1): $(BIN1).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN1).r2: $(R2OBJ1) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS1) $(R2OBJ1) + +$(BIN1): $(BIN1).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +#BIN2 + +$(BIN2).r1: $(R1OBJS2) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC2): $(BIN2).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN2).r2: $(R2OBJ2) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS2) $(R2OBJ2) + +$(BIN2): $(BIN2).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ +# BIN3 + +$(BIN3).r1: $(R1OBJS3) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC3): $(BIN3).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN3).r2: $(R2OBJ3) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS3) $(R2OBJ3) + +$(BIN3): $(BIN3).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN1) $(BIN2) $(BIN3) *.r1 *.r2 *-thunk.S *~ .*.swp + $(call CLEAN) + +distclean: clean + diff --git a/apps/netutils/thttpd/cgi-src/phf.c b/apps/netutils/thttpd/cgi-src/phf.c new file mode 100644 index 000000000..2541481c4 --- /dev/null +++ b/apps/netutils/thttpd/cgi-src/phf.c @@ -0,0 +1,77 @@ +/**************************************************************************** + * netutils/thttpd/cgi-src/phf.c + * Cracker trap + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1996 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/* Old distributions of the NCSA and Apache web servers included a + * version of the phf program that had a bug. The program could + * easily be made to run arbitrary shell commands. There is no real + * legitimate use for phf, so any attempts to run it must be considered + * to be attacks. Accordingly, this version of phf logs the attack + * on stderr and then returns a page on CONFIG_THTTPD_CGI_OUTFD indicating + * that phf doesn't exist. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "config.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char *argv[]) +{ + fprintf(stderr, "phf CGI probe from %s\n", getenv("REMOTE_ADDR")); + + (void)printf("\ +Content-type: text/html\n\ +Status: 404/html\n\ +\n\ +<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n\ +<BODY><H2>404 Not Found</H2>\n\ +The requested object does not exist on this server.\n\ +The link you followed is either outdated, inaccurate,\n\ +or the server has been instructed not to let you have it.\n\ +</BODY></HTML>\n"); + return 0; +} diff --git a/apps/netutils/thttpd/cgi-src/redirect.c b/apps/netutils/thttpd/cgi-src/redirect.c new file mode 100644 index 000000000..84f3b8712 --- /dev/null +++ b/apps/netutils/thttpd/cgi-src/redirect.c @@ -0,0 +1,269 @@ +/**************************************************************************** + * netutils/thttpd/cgi-src/redirect.c + * Simple redirection CGI program + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/* Three steps to set up a redirection: + * + * 1. Make sure your web server is set up to allow CGI programs. + * 2. Make a symbolic link from the file you want to redirect, + * pointing at this program in the CGI bin directory. + * 3. Add an entry to the file ".redirects" in the directory where your + * http server runs CGI programs. For most servers, this is the + * directory where the given CGI program lives. The format of the + * file is a bunch of lines with a filename, whitespace, and the new + * URL. For example: + * + * /test/oldfile.html http://www.acme.com/test/newfile.html + * + * The easiest way to figure out precisely what filename to put into + * .redirects is to set up the symlink and then click on it. You'll get + * back a "404 Not Found" page which includes the filename as received by + * the redirect program, and that's what you want to use. + * + * Note: this is designed for thttpd (http://www.acme.com/software/thttpd/) + * and using it with other web servers may require some hacking. A possible + * gotcha is with the symbolic link from the old file pointing at this + * script - servers other than thttpd may not allow that link to be run + * as a CGI program, because they don't check the link to see that it + * points into the allowed CGI directory. + * + * Note two: It would be really cool to have this program look for + * the .redirects file in the same directory as the file being redirected, + * instead of in the binaries directory. Unfortunately, this appears + * to be impossible with the information CGI gives, plus the non-standardized + * but widespread practice of running CGI programs in the directory where + * the binary lives. Perhaps CGI 1.2 will address this. + */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "config.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +#define LINE_SIZE 80 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static char g_iobuffer[LINE_SIZE]; +static char g_file[LINE_SIZE]; +static char g_url[LINE_SIZE]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void internal_error(char *reason) +{ + char *title = "500 Internal Error"; + + (void)printf("\ +Status: %s\n\ +Content-type: text/html\n\ +\n\ +<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\ +<BODY><H2>%s</H2>\n\ +Something unusual went wrong during a redirection request:\n\ +<BLOCKQUOTE>\n\ +%s\n\ +</BLOCKQUOTE>\n\ +</BODY></HTML>\n", title, title, title, reason); +} + +static void not_found(char *script_name) +{ + char *title = "404 Not Found"; + + (void)printf("\ +Status: %s\n\ +Content-type: text/html\n\ +\n\ +<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\ +<BODY><H2>%s</H2>\n\ +The requested filename, %s, is set up to be redirected to another URL;\n\ +however, the new URL has not yet been specified.\n\ +</BODY></HTML>\n", title, title, title, script_name); +} + +static void moved(char *script_name, char *url) +{ + char *title = "Moved"; + + (void)printf("\ +Location: %s\n\ +Content-type: text/html\n\ +\n\ +<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\ +<BODY><H2>%s</H2>\n\ +The requested filename, %s, has moved to a new URL:\n\ +<A HREF=\"%s\">%s</A>.\n\ +</BODY></HTML>\n", url, title, title, script_name, url, url); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + char *script_name; + char *path_info; + char *cp = 0; + FILE *fp; + char *star; + int err = 0; + + /* Get the name that we were run as, which is the filename being ** + * redirected. + */ + + script_name = getenv("SCRIPT_NAME"); + if (!script_name) + { + internal_error("Couldn't get SCRIPT_NAME environment variable."); + return 1; + } + + /* Append the PATH_INFO, if any. This allows redirection of whole ** + * directories. + */ + + path_info = getenv("PATH_INFO"); + if (path_info) + { + cp = (char *)malloc(strlen(script_name) + strlen(path_info) + 1); + if (!cp) + { + internal_error("Out of memory."); + return 2; + } + + (void)sprintf(cp, "%s%s", script_name, path_info); + script_name = cp; + } + + /* Open the redirects file. */ + + fp = fopen(".redirects", "r"); + if (fp == (FILE *) 0) + { + internal_error("Couldn't open .redirects file."); + err = 3; + goto errout_with_cp; + } + + /* Search the file for a matching entry. */ + + while (fgets(g_iobuffer, LINE_SIZE, fp) != NULL) + { + /* Remove comments. */ + + cp = strchr(g_iobuffer, '#'); + if (cp) + { + *cp = '\0'; + } + + /* Skip leading whitespace. */ + + cp = g_iobuffer; + cp += strspn(cp, " \t"); + + /* Check for blank line. */ + + if (*cp != '\0') + { + /* Parse line. */ + + if (sscanf(cp, "%[^ \t\n] %[^ \t\n]", g_file, g_url) == 2) + { + /* Check for wildcard match. */ + + star = strchr(g_file, '*'); + if (star != (char *)0) + { + /* Check for leading match. */ + + if (strncmp(g_file, script_name, star - g_file) == 0) + { + /* Got it; put together the full name. */ + + strcat(g_url, script_name + (star - g_file)); + + /* XXX Whack the script_name, too? */ + + moved(script_name, g_url); + goto success_out; + } + } + + /* Check for exact match. */ + + if (strcmp(g_file, script_name) == 0) + { + /* Got it. */ + + moved(script_name, g_url); + goto success_out; + } + } + } + } + + /* No match found. */ + + not_found(script_name); + err = 4; + +success_out: + fclose(fp); +errout_with_cp: + if (cp) + { + free(cp); + } + return err; +} diff --git a/apps/netutils/thttpd/cgi-src/ssi.c b/apps/netutils/thttpd/cgi-src/ssi.c new file mode 100644 index 000000000..4afb141f9 --- /dev/null +++ b/apps/netutils/thttpd/cgi-src/ssi.c @@ -0,0 +1,957 @@ +/**************************************************************************** + * netutils/thttpd/cgi-src/ssi.c + * Server-side-includes CGI program + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <nuttx/regex.h> + +#include "config.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +#define ST_GROUND 0 +#define ST_LESSTHAN 1 +#define ST_BANG 2 +#define ST_MINUS1 3 +#define ST_MINUS2 4 + +#define SF_BYTES 0 +#define SF_ABBREV 1 + +#define DI_CONFIG 0 +#define DI_INCLUDE 1 +#define DI_ECHO 2 +#define DI_FSIZE 3 +#define DI_FLASTMOD 4 + +#define BUFFER_SIZE 512 +#define TIMEFMT_SIZE 80 +#define MAX_TAGS 32 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void read_file(FILE *instream, char *vfilename, char *filename); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static char *g_url; +static char g_timeformat[TIMEFMT_SIZE]; +static char g_iobuffer1[BUFFER_SIZE]; +static char g_iobuffer2[BUFFER_SIZE]; +static char *g_tags[MAX_TAGS]; +static int g_sizefmt; +static struct stat g_sb; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void internal_error(char *reason) +{ + char *title = "500 Internal Error"; + + (void)printf("\ +<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\ +<BODY><H2>%s</H2>\n\ +Something unusual went wrong during a server-side-includes request:\n\ +<BLOCKQUOTE>\n\ +%s\n\ +</BLOCKQUOTE>\n\ +</BODY></HTML>\n", title, title, reason); +} + +static void not_found(char *filename) +{ + char *title = "404 Not Found"; + + (void)printf("\ +<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\ +<BODY><H2>%s</H2>\n\ +The requested server-side-includes filename, %s,\n\ +does not seem to exist.\n\ +</BODY></HTML>\n", title, title, filename); +} + +static void not_found2(char *directive, char *tag, char *filename) +{ + char *title = "Not Found"; + + (void)printf("\ +<HR><H2>%s</H2>\n\ +The filename requested in a %s %s directive, %s,\n\ +does not seem to exist.\n\ +<HR>\n", title, directive, tag, filename); +} + +static void not_permitted(char *directive, char *tag, char *val) +{ + char *title = "Not Permitted"; + + (void)printf("\ +<HR><H2>%s</H2>\n\ +The filename requested in the %s %s=%s directive\n\ +may not be fetched.\n\ +<HR>\n", title, directive, tag, val); +} + +static void unknown_directive(char *filename, char *directive) +{ + char *title = "Unknown Directive"; + + (void)printf("\ +<HR><H2>%s</H2>\n\ +The requested server-side-includes filename, %s,\n\ +tried to use an unknown directive, %s.\n\ +<HR>\n", title, filename, directive); +} + +static void unknown_tag(char *filename, char *directive, char *tag) +{ + char *title = "Unknown Tag"; + + (void)printf("\ +<HR><H2>%s</H2>\n\ +The requested server-side-includes filename, %s,\n\ +tried to use the directive %s with an unknown tag, %s.\n\ +<HR>\n", title, filename, directive, tag); +} + +static void unknown_value(char *filename, char *directive, char *tag, char *val) +{ + char *title = "Unknown Value"; + + (void)printf("\ +<HR><H2>%s</H2>\n\ +The requested server-side-includes filename, %s,\n\ +tried to use the directive %s %s with an unknown value, %s.\n\ +<HR>\n", title, filename, directive, tag, val); +} + +static int get_filename(char *vfilename, char *filename, + char *directive, char *tag, char *val, char *fn, + int fnsize) +{ + char *cp; + int vl; + int fl; + + /* Used for the various commands that accept a file name. These commands + * accept two tags: virtual Gives a virtual path to a document on the + * server. file Gives a pathname relative to the current directory. ../ + * cannot be used in this pathname, nor can absolute paths be used. + */ + + vl = strlen(vfilename); + fl = strlen(filename); + + if (strcmp(tag, "virtual") == 0) + { + if (strstr(val, "../") != (char *)0) + { + not_permitted(directive, tag, val); + return -1; + } + + /* Figure out root using difference between vfilename and filename. */ + + if (vl > fl || strcmp(vfilename, &filename[fl - vl]) != 0) + { + return -1; + } + + if (fl - vl + strlen(val) >= fnsize) + { + return -1; + } + + (void)strncpy(fn, filename, fl - vl); + (void)strcpy(&fn[fl - vl], val); + } + else if (strcmp(tag, "file") == 0) + { + if (val[0] == '/' || strstr(val, "../") != (char *)0) + { + not_permitted(directive, tag, val); + return -1; + } + if (fl + 1 + strlen(val) >= fnsize) + { + return -1; + } + + (void)strcpy(fn, filename); + cp = strrchr(fn, '/'); + if (cp == (char *)0) + { + cp = &fn[strlen(fn)]; + *cp = '/'; + } + (void)strcpy(++cp, val); + } + else + { + unknown_tag(filename, directive, tag); + return -1; + } + return 0; +} + +static int check_filename(char *filename) +{ + static int inited = 0; + static char *cgi_pattern; +#ifdef CONFIG_AUTH_FILE + struct stat sb; + char *dirname; + char *authname; + char *cp; + int fnl; + int r; +#endif + + if (!inited) + { + /* Get the cgi pattern. */ + + cgi_pattern = getenv("CGI_PATTERN"); +#ifdef CGI_PATTERN + if (cgi_pattern == (char *)0) + { + cgi_pattern = CGI_PATTERN; + } +#endif /* CGI_PATTERN */ + inited = 1; + } + + /* ../ is not permitted. */ + + if (strstr(filename, "../") !=NULL) + { + return 0; + } + + /* Ensure that we are not reading a basic auth password file. */ + +#ifdef CONFIG_AUTH_FILE + fnl = strlen(filename); + if (strcmp(filename, CONFIG_AUTH_FILE) == 0 || + (fnl >= sizeof(CONFIG_AUTH_FILE) && + strcmp(&filename[fnl - sizeof(CONFIG_AUTH_FILE) + 1], CONFIG_AUTH_FILE) == 0 && + filename[fnl - sizeof(CONFIG_AUTH_FILE)] == '/')) + { + return 0; + } + + /* Check for an auth file in the same directory. We can't do an actual ** + * auth password check here because CGI programs are not given the ** + * authorization header, for security reasons. So instead we just ** + * prohibit access to all auth-protected files. + */ + + dirname = strdup(filename); + if (dirname == (char *)0) + { + /* out of memory */ + + return 0; + } + + cp = strrchr(dirname, '/'); + if (cp == (char *)0) + { + (void)strcpy(dirname, "."); + } + else + { + *cp = '\0'; + } + + authname = malloc(strlen(dirname) + 1 + sizeof(CONFIG_AUTH_FILE)); + if (!authname) + { + /* out of memory */ + + free(dirname); + return 0; + } + + (void)sprintf(authname, "%s/%s", dirname, CONFIG_AUTH_FILE); + r = stat(authname, &sb); + + free(dirname); + free(authname); + + if (r == 0) + { + return 0; + } +#endif /* CONFIG_AUTH_FILE */ + + /* Ensure that we are not reading a CGI file. */ + + if (cgi_pattern != (char *)0 && match(cgi_pattern, filename)) + { + return 0; + } + return 1; +} + +static void show_time(time_t t, int gmt) +{ + struct tm *tmP; + + if (gmt) + { + tmP = gmtime(&t); + } + else + { + tmP = localtime(&t); + } + + if (strftime(g_iobuffer2, BUFFER_SIZE, g_timeformat, tmP) > 0) + { + (void)puts(g_iobuffer2); + } +} + +static void show_size(off_t size) +{ + switch (g_sizefmt) + { + case SF_BYTES: + (void)printf("%ld", (long)size); /* spec says should have commas */ + break; + + case SF_ABBREV: + if (size < 1024) + { + (void)printf("%ld", (long)size); + } + else if (size < 1024) + { + (void)printf("%ldK", (long)size / 1024L); + } + else if (size < 1024 * 1024) + { + (void)printf("%ldM", (long)size / (1024L * 1024L)); + } + else + { + (void)printf("%ldG", (long)size / (1024L * 1024L * 1024L)); + } + break; + } +} + +static void do_config(FILE *instream, char *vfilename, char *filename, + char *directive, char *tag, char *val) +{ + /* The config directive controls various aspects of the file parsing. ** + * There are two valid tags: g_timeformat Gives the server a new format to + * use when providing dates. This is a string compatible with the + * strftime library call. g_sizefmt Determines the formatting to be used + * when displaying the size of a file. Valid choices are bytes, for a + * formatted byte count (formatted as 1,234,567), or abbrev for an + * abbreviated version displaying the number of kilobytes or megabytes the + * file occupies. + */ + + if (strcmp(tag, "g_timeformat") == 0) + { + (void)strncpy(g_timeformat, val, TIMEFMT_SIZE - 1); + g_timeformat[TIMEFMT_SIZE - 1] = '\0'; + } + else if (strcmp(tag, "g_sizefmt") == 0) + { + if (strcmp(val, "bytes") == 0) + { + g_sizefmt = SF_BYTES; + } + else if (strcmp(val, "abbrev") == 0) + { + g_sizefmt = SF_ABBREV; + } + else + { + unknown_value(filename, directive, tag, val); + } + } + else + { + unknown_tag(filename, directive, tag); + } +} + +static void do_include(FILE *instream, char *vfilename, char *filename, + char *directive, char *tag, char *val) +{ + FILE *instream2; + int ret; + + /* Inserts the text of another document into the parsed document. */ + + ret = get_filename(vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE); + if (ret < 0) + { + return; + } + + if (!check_filename(g_iobuffer1)) + { + not_permitted(directive, tag, g_iobuffer1); + return; + } + + instream2 = fopen(g_iobuffer1, "r"); + if (instream2 == (FILE *) 0) + { + not_found2(directive, tag, g_iobuffer1); + return; + } + + if (strcmp(tag, "virtual") == 0) + { + if (strlen(val) <BUFFER_SIZE) + { + (void)strcpy(g_iobuffer2, val); + } + else + { + (void)strcpy(g_iobuffer2, g_iobuffer1); /* same size, has to fit */ + } + } + else + { + if (strlen(vfilename) + 1 + strlen(val) < BUFFER_SIZE) + { + char *cp; + (void)strcpy(g_iobuffer2, vfilename); + cp = strrchr(g_iobuffer2, '/'); + if (cp == (char *)0) + { + cp = &g_iobuffer2[strlen(g_iobuffer2)]; + *cp = '/'; + } + (void)strcpy(++cp, val); + } + else + { + (void)strcpy(g_iobuffer2, g_iobuffer1); /* same size, has to fit */ + } + } + + read_file(instream2, g_iobuffer2, g_iobuffer1); + (void)fclose(instream2); +} + +static void do_echo(FILE *instream, char *vfilename, char *filename, + char *directive, char *tag, char *val) +{ + char *cp; + + /* Prints the value of one of the include variables. Any dates are + * printed subject to the currently configured g_timeformat. The only valid + * tag is var, whose value is the name of the variable you wish to echo. + */ + + if (strcmp(tag, "var") != 0) + { + unknown_tag(filename, directive, tag); + } + else + { + if (strcmp(val, "DOCUMENT_NAME") == 0) + { + /* The current filename. */ + + (void)puts(filename); + } + else if (strcmp(val, "DOCUMENT_URI") == 0) + { + /* The virtual path to this file (such as /~robm/foo.shtml). */ + + (void)puts(vfilename); + } + else if (strcmp(val, "QUERY_STRING_UNESCAPED") == 0) + { + /* The unescaped version of any search query the client sent. */ + + cp = getenv("QUERY_STRING"); + if (cp != (char *)0) + { + (void)puts(cp); + } + } + else if (strcmp(val, "DATE_LOCAL") == 0) + { + struct timeval tm; + + /* The current date, local time zone. */ + + gettimeofday(&tm, NULL); + show_time(tm.tv_sec, 0); + } + else if (strcmp(val, "DATE_GMT") == 0) + { + struct timeval tm; + + /* Same as DATE_LOCAL but in Greenwich mean time. */ + + gettimeofday(&tm, NULL); + show_time(tm.tv_sec, 1); + } + else if (strcmp(val, "LAST_MODIFIED") == 0) + { + /* The last modification date of the current document. */ + + if (fstat(fileno(instream), &g_sb) >= 0) + { + show_time(g_sb.st_mtime, 0); + } + } + else + { + /* Try an environment variable. */ + + cp = getenv(val); + if (cp == (char *)0) + { + unknown_value(filename, directive, tag, val); + } + else + { + (void)puts(cp); + } + } + } +} + +static void do_fsize(FILE *instream, char *vfilename, char *filename, + char *directive, char *tag, char *val) +{ + int ret; + + /* Prints the size of the specified file. */ + + ret = get_filename(vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE); + if (ret < 0) + { + return; + } + + if (stat(g_iobuffer1, &g_sb) < 0) + { + not_found2(directive, tag, g_iobuffer1); + return; + } + + show_size(g_sb.st_size); +} + +static void do_flastmod(FILE *instream, char *vfilename, char *filename, + char *directive, char *tag, char *val) +{ + int ret; + + /* Prints the last modification date of the specified file. */ + + ret = get_filename(vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE); + if (ret < 0) + { + return; + } + + if (stat(g_iobuffer1, &g_sb) < 0) + { + not_found2(directive, tag, g_iobuffer1); + return; + } + show_time(g_sb.st_mtime, 0); +} + +static void parse(FILE *instream, char *vfilename, char *filename, char *str) +{ + char *directive; + char *cp; + int ntags; + int dirn; + int i; + char *val; + + directive = str; + directive += strspn(directive, " \t\n\r"); + + ntags = 0; + cp = directive; + for (;;) + { + cp = strpbrk(cp, " \t\n\r\""); + if (cp == (char *)0) + { + break; + } + + if (*cp == '"') + { + cp = strpbrk(cp + 1, "\""); + cp++; + if (*cp == '\0') + { + break; + } + } + + *cp++ = '\0'; + cp += strspn(cp, " \t\n\r"); + if (*cp == '\0') + { + break; + } + + if (ntags < MAX_TAGS) + { + g_tags[ntags++] = cp; + } + } + + if (strcmp(directive, "config") == 0) + { + dirn = DI_CONFIG; + } + else if (strcmp(directive, "include") == 0) + { + dirn = DI_INCLUDE; + } + else if (strcmp(directive, "echo") == 0) + { + dirn = DI_ECHO; + } + else if (strcmp(directive, "fsize") == 0) + { + dirn = DI_FSIZE; + } + else if (strcmp(directive, "flastmod") == 0) + { + dirn = DI_FLASTMOD; + } + else + { + unknown_directive(filename, directive); + return; + } + + for (i = 0; i < ntags; ++i) + { + if (i > 0) + { + putchar(' '); + } + + val = strchr(g_tags[i], '='); + if (val == (char *)0) + { + val = ""; + } + else + { + *val++ = '\0'; + } + + if (*val == '"' && val[strlen(val) - 1] == '"') + { + val[strlen(val) - 1] = '\0'; + ++val; + } + + switch (dirn) + { + case DI_CONFIG: + do_config(instream, vfilename, filename, directive, g_tags[i], val); + break; + + case DI_INCLUDE: + do_include(instream, vfilename, filename, directive, g_tags[i], val); + break; + + case DI_ECHO: + do_echo(instream, vfilename, filename, directive, g_tags[i], val); + break; + + case DI_FSIZE: + do_fsize(instream, vfilename, filename, directive, g_tags[i], val); + break; + + case DI_FLASTMOD: + do_flastmod(instream, vfilename, filename, directive, g_tags[i], val); + break; + } + } +} + +static void slurp(FILE *instream, char *vfilename, char *filename) +{ + int state; + int ich; + int i; + + /* Now slurp in the rest of the comment from the input file. */ + + i = 0; + state = ST_GROUND; + while ((ich = getc(instream)) != EOF) + { + switch (state) + { + case ST_GROUND: + if (ich == '-') + { + state = ST_MINUS1; + } + break; + + case ST_MINUS1: + if (ich == '-') + { + state = ST_MINUS2; + } + else + { + state = ST_GROUND; + } + break; + + case ST_MINUS2: + if (ich == '>') + { + g_iobuffer1[i - 2] = '\0'; + parse(instream, vfilename, filename, g_iobuffer1); + return; + } + else if (ich != '-') + { + state = ST_GROUND; + } + break; + } + + if (i < BUFFER_SIZE - 1) + { + g_iobuffer1[i++] = (char)ich; + } + } +} + +static void read_file(FILE *instream, char *vfilename, char *filename) +{ + int ich; + int state; + + /* Copy it to output, while running a state-machine to look for SSI + * directives. + */ + + state = ST_GROUND; + while ((ich = getc(instream)) != EOF) + { + switch (state) + { + case ST_GROUND: + if (ich == '<') + { + state = ST_LESSTHAN; + continue; + } + break; + + case ST_LESSTHAN: + if (ich == '!') + { + state = ST_BANG; + continue; + } + else + { + state = ST_GROUND; + putchar('<'); + } + break; + + case ST_BANG: + if (ich == '-') + { + state = ST_MINUS1; + continue; + } + else + { + state = ST_GROUND; + (void)puts("<!"); + } + break; + + case ST_MINUS1: + if (ich == '-') + { + state = ST_MINUS2; + continue; + } + else + { + state = ST_GROUND; + (void)puts("<!-"); + } + break; + + case ST_MINUS2: + if (ich == '#') + { + slurp(instream, vfilename, filename); + state = ST_GROUND; + continue; + } + else + { + state = ST_GROUND; + (void)puts("<!--"); + } + break; + } + + putchar((char)ich); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + FILE *instream; + char *script_name; + char *path_info; + char *path_translated; + int err = 0; + + /* Default formats. */ + + (void)strcpy(g_timeformat, "%a %b %e %T %Z %Y"); + g_sizefmt = SF_BYTES; + + /* The MIME type has to be text/html. */ + + (void)puts("Content-type: text/html\n\n"); + + /* Get the name that we were run as. */ + + script_name = getenv("SCRIPT_NAME"); + if (!script_name) + { + internal_error("Couldn't get SCRIPT_NAME environment variable."); + return 1; + } + + /* Append the PATH_INFO, if any, to get the full URL. */ + + path_info = getenv("PATH_INFO"); + if (!path_info) + { + path_info = ""; + } + + g_url = (char*)malloc(strlen(script_name) + strlen(path_info) + 1); + if (!g_url) + { + internal_error("Out of memory."); + return 2; + } + (void)sprintf(g_url, "%s%s", script_name, path_info); + + /* Get the name of the file to parse. */ + + path_translated = getenv("PATH_TRANSLATED"); + if (!path_translated) + { + internal_error("Couldn't get PATH_TRANSLATED environment variable."); + err = 3; + goto errout_with_g_url; + } + + if (!check_filename(path_translated)) + { + not_permitted("initial", "PATH_TRANSLATED", path_translated); + err = 4; + goto errout_with_g_url; + } + + /* Open it. */ + + instream = fopen(path_translated, "r"); + if (!instream) + { + not_found(path_translated); + err = 5; + goto errout_with_g_url; + } + + /* Read and handle the file. */ + + read_file(instream, path_info, path_translated); + + (void)fclose(instream); + +errout_with_g_url: + free(g_url); + return err; +} diff --git a/apps/netutils/thttpd/config.h b/apps/netutils/thttpd/config.h new file mode 100644 index 000000000..f1b4c2d4c --- /dev/null +++ b/apps/netutils/thttpd/config.h @@ -0,0 +1,253 @@ +/**************************************************************************** + * netutils/thttpd/config.h + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NETUTILS_THTTPD_CONFIG_H +#define __NETUTILS_THTTPD_CONFIG_H + +/**************************************************************************** + * Included files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/compiler.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Make sure that the system is configured to handle THTTPD */ + +#undef CONFIG_THTTPD +#if defined(CONFIG_NET) && defined(CONFIG_NET_TCP) && \ + defined(CONFIG_NET_TCPBACKLOG) && !defined(CONFIG_DISABLE_ENVIRONMENT) && \ + !defined(CONFIG_SDCLONE_DISABLE) && CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 + +# define CONFIG_THTTPD 1 + +/* Check all THTTPD configuration settings. Complain on any that should have + * been defined but were not. Supply some kind of reasonable value for all + * undefined settings. + */ + +/* Server port number */ + +# ifndef CONFIG_THTTPD_PORT +# define CONFIG_THTTPD_PORT 80 +# endif + +/* Server IP address (no host name) */ + +# ifndef CONFIG_THTTPD_IPADDR +# ifdef CONFIG_CPP_HAVE_WARNING +# warning "CONFIG_THTTPD_IPADDR not defined" +# endif +# define CONFIG_THTTPD_IPADDR (10<<24|0<<16|0<<8|2) +# endif + +/* SERVER_ADDRESS: response */ + +# ifndef CONFIG_THTTPD_SERVER_ADDRESS +# define CONFIG_THTTPD_SERVER_ADDRESS "http://www.nuttx.org" +# endif + +/* SERVER_SOFTWARE: response */ + +# ifndef CONFIG_THTTPD_SERVER_SOFTWARE +# define CONFIG_THTTPD_SERVER_SOFTWARE "thttpd/2.25b 29dec2003-NuttX" +# endif + +# ifndef CONFIG_THTTPD_PATH +# ifdef CONFIG_CPP_HAVE_WARNING +# warning "CONFIG_THTTPD_PATH not defined" +# endif +# define CONFIG_THTTPD_PATH "/mnt/www" +# endif + +# ifndef CONFIG_THTTPD_CGI_PATH +# ifdef CONFIG_CPP_HAVE_WARNING +# warning "CONFIG_THTTPD_CGI_PATH not defined" +# endif +# define CONFIG_THTTPD_CGI_PATH "/mnt/www/cgi-bin" +# endif + +/* Only CGI programs whose fully expanded pathes match this pattern will be executed. In fact, + * if this value is not defined then no CGI logic will be built. + */ + +# ifndef CONFIG_THTTPD_CGI_PATTERN +# define CONFIG_THTTPD_CGI_PATTERN "/mnt/www/cgi-bin/*" +# endif + +/* These provide the priority and stack size of the CGI child tasks */ + +# ifndef CONFIG_THTTPD_CGI_PRIORITY +# define CONFIG_THTTPD_CGI_PRIORITY 50 +# endif + +# ifndef CONFIG_THTTPD_CGI_STACKSIZE +# define CONFIG_THTTPD_CGI_STACKSIZE 2048 +# endif + +/* Byte output limit for CGI tasks */ + +# ifndef CONFIG_THTTPD_CGI_BYTECOUNT +# define CONFIG_THTTPD_CGI_BYTECOUNT 200000 +# endif + +/* How many seconds to allow CGI programs to run before killing them. */ + +# ifndef CONFIG_THTTPD_CGI_TIMELIMIT +# define CONFIG_THTTPD_CGI_TIMELIMIT 0 /* No time limit */ +# endif + +/* The default character set name to use with text MIME types. */ + +# ifndef CONFIG_THTTPD_CHARSET +# define CONFIG_THTTPD_CHARSET "iso-8859-1" +# endif + +/* Initial buffer size, buffer reallocation increment, maximum buffer size */ + +# ifndef CONFIG_THTTPD_IOBUFFERSIZE +# define CONFIG_THTTPD_IOBUFFERSIZE 256 +# endif + +# ifndef CONFIG_THTTPD_MINSTRSIZE +# define CONFIG_THTTPD_MINSTRSIZE 64 +# endif + +# ifndef CONFIG_THTTPD_REALLOCINCR +# define CONFIG_THTTPD_REALLOCINCR 64 +# endif + +# ifndef CONFIG_THTTPD_MAXREALLOC +# define CONFIG_THTTPD_MAXREALLOC 4096 +# endif + +# ifndef CONFIG_THTTPD_CGIINBUFFERSIZE +# define CONFIG_THTTPD_CGIINBUFFERSIZE 512 /* Size of buffer to interpose input */ +# endif + +# ifndef CONFIG_THTTPD_CGIOUTBUFFERSIZE +# define CONFIG_THTTPD_CGIOUTBUFFERSIZE 512 /* Size of buffer to interpose output */ +# endif + +# if CONFIG_THTTPD_IOBUFFERSIZE > 65535 +# error "Can't use uint16_t for buffer size" +# endif + +/* A list of index filenames to check. The files are searched for in this order. */ + +# ifndef CONFIG_THTTPD_INDEX_NAMES +# define CONFIG_THTTPD_INDEX_NAMES "index.html", "index.htm", "index.cgi" +# endif + +/* CONFIG_AUTH_FILE - The file to use for authentication. If this is defined then + * thttpd checks for this file in the local directory before every fetch. If the + * file exists then authentication is done, otherwise the fetch proceeds as usual. + * If you leave this undefined then thttpd will not implement authentication at + * all and will not check for auth files, which saves a bit of CPU time. + * A typical value is ".htpasswd" + */ + +/* The listen() backlog queue length. */ + +# ifndef CONFIG_THTTPD_LISTEN_BACKLOG +# define CONFIG_THTTPD_LISTEN_BACKLOG 8 +# endif + +/* How many milliseconds to leave a connection open while doing a lingering close */ + +# ifndef CONFIG_THTTPD_LINGER_MSEC +# define CONFIG_THTTPD_LINGER_MSEC 500 +# endif + +/* How often to run the occasional cleanup job.*/ + +# ifndef CONFIG_THTTPD_OCCASIONAL_MSEC +# define CONFIG_THTTPD_OCCASIONAL_MSEC 120 /* Two minutes */ +# endif + +/* How many seconds to allow for reading the initial request on a new connection. */ + +# ifndef CONFIG_THTTPD_IDLE_READ_LIMIT_SEC +# define CONFIG_THTTPD_IDLE_READ_LIMIT_SEC 300 +# endif + +/* How many seconds before an idle connection gets closed. */ + +# ifndef CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC +# define CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC 300 +# endif + +/* Memory debug instrumentation depends on other debug options */ + +#if (!defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_NET)) && defined(CONFIG_THTTPD_MEMDEBUG) +# undef CONFIG_THTTPD_MEMDEBUG +#endif + +/* Tilde mapping. Many URLs use ~username to indicate a user's home directory. thttpd + * provides two options for mapping this construct to an actual filename. + * + * 1) Map ~username to <prefix>/username. This is the recommended choice. Each user + * gets a subdirectory in the main web tree, and the tilde construct points there. + * The prefix could be something like "users", or it could be empty. + * 2) Map ~username to <user's homedir>/<postfix>. The postfix would be the name of + * a subdirectory off of the user's actual home dir, something like "public_html". + * + * You can also leave both options undefined, and thttpd will not do anything special + * about tildes. Enabling both options is an error. + * + * Typical values, if they're defined, are "users" for CONFIG_THTTPD_TILDE_MAP1 and "public_html" + * for CONFIG_THTTPD_TILDE_MAP2. + */ + +# if defined(CONFIG_THTTPD_TILDE_MAP1) && defined(CONFIG_THTTPD_TILDE_MAP2) +# error "Both CONFIG_THTTPD_TILDE_MAP1 andCONFIG_THTTPD_TILDE_MAP2 are defined" +# endif + +/* If CONFIG_THTTPD_URLPATTERN is defined, then it will be used to match and verify + * referrers. + */ + +#else /* Dependencies not provided */ +# ifdef CONFIG_CPP_HAVE_WARNING +# warning "THTTPD not built because dependencies not selected in configuration" +# endif +#endif /* Dependencies not provided */ + +#endif /* __NETUTILS_THTTPD_CONFIG_H */ + diff --git a/apps/netutils/thttpd/fdwatch.c b/apps/netutils/thttpd/fdwatch.c new file mode 100644 index 000000000..24ea7a1e0 --- /dev/null +++ b/apps/netutils/thttpd/fdwatch.c @@ -0,0 +1,371 @@ +/**************************************************************************** + * netutils/thttpd/timers.c + * FD watcher routines for poll() + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1999,2000 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdlib.h> +#include <debug.h> +#include <poll.h> +#include <debug.h> + +#include "config.h" +#include "thttpd_alloc.h" +#include "fdwatch.h" + +#ifdef CONFIG_THTTPD + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/* Debug output from this file is normally suppressed. If enabled, be aware + * that output to stdout will interfere with CGI programs (you could use the + * the low-level debug (lldbg) functions which probably do not use stdout + */ + +#ifdef CONFIG_THTTPD_FDWATCH_DEBUG +# ifdef CONFIG_CPP_HAVE_VARARGS +# define fwdbg(format, arg...) ndbg(format, ##arg) +# define fwlldbg(format, arg...) nlldbg(format, ##arg) +# define fwvdbg(format, arg...) nvdbg(format, ##arg) +# define fwllvdbg(format, arg...) nllvdbg(format, ##arg) +# else +# define fwdbg ndbg +# define fwlldbg nlldbg +# define fwvdbg nvdbg +# define fwllvdbg nllvdbg +# endif +#else +# ifdef CONFIG_CPP_HAVE_VARARGS +# define fwdbg(x...) +# define fwlldbg(x...) +# define fwvdbg(x...) +# define fwllvdbg(x...) +# else +# define fwdbg (void) +# define fwlldbg (void) +# define fwvdbg (void) +# define fwllvdbg (void) +# endif +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_THTTPD_FDWATCH_DEBUG +static void fdwatch_dump(const char *msg, FAR struct fdwatch_s *fw) +{ + int i; + + fwvdbg("%s\n", msg); + fwvdbg("nwatched: %d nfds: %d\n", fw->nwatched, fw->nfds); + for (i = 0; i < fw->nwatched; i++) + { + fwvdbg("%2d. pollfds: {fd: %d events: %02x revents: %02x} client: %p\n", + i+1, fw->pollfds[i].fd, fw->pollfds[i].events, + fw->pollfds[i].revents, fw->client[i]); + } + fwvdbg("nactive: %d next: %d\n", fw->nactive, fw->next); + for (i = 0; i < fw->nactive; i++) + { + fwvdbg("%2d. %d active\n", i, fw->ready[i]); + } +} +#else +# define fdwatch_dump(m,f) +#endif + +static int fdwatch_pollndx(FAR struct fdwatch_s *fw, int fd) +{ + int pollndx; + + /* Get the index associated with the fd */ + + for (pollndx = 0; pollndx < fw->nwatched; pollndx++) + { + if (fw->pollfds[pollndx].fd == fd) + { + fwvdbg("pollndx: %d\n", pollndx); + return pollndx; + } + } + + fwdbg("No poll index for fd %d: %d\n", fd); + return -1; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* Initialize the fdwatch data structures. Returns -1 on failure. */ + +struct fdwatch_s *fdwatch_initialize(int nfds) +{ + FAR struct fdwatch_s *fw; + + /* Allocate the fdwatch data structure */ + + fw = (struct fdwatch_s*)zalloc(sizeof(struct fdwatch_s)); + if (!fw) + { + fwdbg("Failed to allocate fdwatch\n"); + return NULL; + } + + /* Initialize the fdwatch data structures. */ + + fw->nfds = nfds; + + fw->client = (void**)httpd_malloc(sizeof(void*) * nfds); + if (!fw->client) + { + goto errout_with_allocations; + } + + fw->pollfds = (struct pollfd*)httpd_malloc(sizeof(struct pollfd) * nfds); + if (!fw->pollfds) + { + goto errout_with_allocations; + } + + fw->ready = (uint8_t*)httpd_malloc(sizeof(uint8_t) * nfds); + if (!fw->ready) + { + goto errout_with_allocations; + } + + fdwatch_dump("Initial state:", fw); + return fw; + +errout_with_allocations: + fdwatch_uninitialize(fw); + return NULL; +} + +/* Uninitialize the fwdatch data structure */ + +void fdwatch_uninitialize(struct fdwatch_s *fw) +{ + if (fw) + { + fdwatch_dump("Uninitializing:", fw); + if (fw->client) + { + httpd_free(fw->client); + } + + if (fw->pollfds) + { + httpd_free(fw->pollfds); + } + + if (fw->ready) + { + httpd_free(fw->ready); + } + + httpd_free(fw); + } +} + +/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */ + +void fdwatch_add_fd(struct fdwatch_s *fw, int fd, void *client_data) +{ + fwvdbg("fd: %d client_data: %p\n", fd, client_data); + fdwatch_dump("Before adding:", fw); + + if (fw->nwatched >= fw->nfds) + { + fwdbg("too many fds\n"); + return; + } + + /* Save the new fd at the end of the list */ + + fw->pollfds[fw->nwatched].fd = fd; + fw->pollfds[fw->nwatched].events = POLLIN; + fw->client[fw->nwatched] = client_data; + + /* Increment the count of watched descriptors */ + + fw->nwatched++; + fdwatch_dump("After adding:", fw); +} + +/* Remove a descriptor from the watch list. */ + +void fdwatch_del_fd(struct fdwatch_s *fw, int fd) +{ + int pollndx; + + fwvdbg("fd: %d\n", fd); + fdwatch_dump("Before deleting:", fw); + + /* Get the index associated with the fd */ + + pollndx = fdwatch_pollndx(fw, fd); + if (pollndx >= 0) + { + /* Decrement the number of fds in the poll table */ + + fw->nwatched--; + + /* Replace the deleted one with the one at the the end + * of the list. + */ + + if (pollndx != fw->nwatched) + { + fw->pollfds[pollndx] = fw->pollfds[fw->nwatched]; + fw->client[pollndx] = fw->client[fw->nwatched]; + } + } + fdwatch_dump("After deleting:", fw); +} + +/* Do the watch. Return value is the number of descriptors that are ready, + * or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means + * wait indefinitely. + */ + +int fdwatch(struct fdwatch_s *fw, long timeout_msecs) +{ + int ret; + int i; + + /* Wait for activity on any of the desciptors. When poll() returns, ret + * will hold the number of descriptors with activity (or zero on a timeout + * or <0 on an error. + */ + + fdwatch_dump("Before waiting:", fw); + fwvdbg("Waiting... (timeout %d)\n", timeout_msecs); + fw->nactive = 0; + fw->next = 0; + ret = poll(fw->pollfds, fw->nwatched, (int)timeout_msecs); + fwvdbg("Awakened: %d\n", ret); + + /* Look through all of the descriptors and make a list of all of them than + * have activity. + */ + + if (ret > 0) + { + for (i = 0; i < fw->nwatched; i++) + { + /* Is there activity on this descriptor? */ + + if (fw->pollfds[i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) + { + /* Yes... save it in a shorter list */ + + fwvdbg("pollndx: %d fd: %d revents: %04x\n", + i, fw->pollfds[i].fd, fw->pollfds[i].revents); + + fw->ready[fw->nactive++] = fw->pollfds[i].fd; + if (fw->nactive == ret) + { + /* We have all of them, break out early */ + + break; + } + } + } + } + + /* Return the number of descriptors with activity */ + + fwvdbg("nactive: %d\n", fw->nactive); + fdwatch_dump("After wakeup:", fw); + return ret; +} + +/* Check if a descriptor was ready. */ + +int fdwatch_check_fd(struct fdwatch_s *fw, int fd) +{ + int pollndx; + + fwvdbg("fd: %d\n", fd); + fdwatch_dump("Checking:", fw); + + /* Get the index associated with the fd */ + + pollndx = fdwatch_pollndx(fw, fd); + if (pollndx >= 0 && (fw->pollfds[pollndx].revents & POLLERR) == 0) + { + return fw->pollfds[pollndx].revents & (POLLIN | POLLHUP | POLLNVAL); + } + + fwvdbg("POLLERR fd: %d\n", fd); + return 0; +} + +void *fdwatch_get_next_client_data(struct fdwatch_s *fw) +{ + fdwatch_dump("Before getting client data:", fw); + if (fw->next >= fw->nwatched) + { + fwvdbg("All client data returned: %d\n", fw->next); + return (void*)-1; + } + + fwvdbg("client_data[%d]: %p\n", fw->next, fw->client[fw->next]); + return fw->client[fw->next++]; +} + +#endif /* CONFIG_THTTPD */ + diff --git a/apps/netutils/thttpd/fdwatch.h b/apps/netutils/thttpd/fdwatch.h new file mode 100644 index 000000000..e60727db1 --- /dev/null +++ b/apps/netutils/thttpd/fdwatch.h @@ -0,0 +1,111 @@ +/**************************************************************************** + * netutils/thttpd/fdwatch.h + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in THTTPD: + * + * Copyright © 1999 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NETUTILS_THTTPD_FDWATCH_H +#define __NETUTILS_THTTPD_FDWATCH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/* Define to enable detailed FDWATCH debug output */ + +#undef CONFIG_THTTPD_FDWATCH_DEBUG + +#ifndef INFTIM +# define INFTIM -1 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct fdwatch_s +{ + struct pollfd *pollfds; /* Poll data (allocated) */ + void **client; /* Client data (allocated) */ + uint8_t *ready; /* The list of fds with activity (allocated) */ + uint8_t nfds; /* The configured maximum number of fds */ + uint8_t nwatched; /* The number of fds currently watched */ + uint8_t nactive; /* The number of fds with activity */ + uint8_t next; /* The index to the next client data */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Initialize the fdwatch data structures. Returns NULL on failure. */ + +extern struct fdwatch_s *fdwatch_initialize(int nfds); + +/* Uninitialize the fwdatch data structure */ + +extern void fdwatch_uninitialize(struct fdwatch_s *fw); + +/* Add a descriptor to the watch list */ + +extern void fdwatch_add_fd(struct fdwatch_s *fw, int fd, void *client_data); + +/* Delete a descriptor from the watch list. */ + +extern void fdwatch_del_fd(struct fdwatch_s *fw, int fd); + +/* Do the watch. Return value is the number of descriptors that are ready, + * or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means + * wait indefinitely. + */ + +extern int fdwatch(struct fdwatch_s *fw, long timeout_msecs); + +/* Check if a descriptor was ready. */ + +extern int fdwatch_check_fd(struct fdwatch_s *fw, int fd); + +/* Get the client data for the next returned event. Returns -1 when there + * are no more events. + */ + +extern void *fdwatch_get_next_client_data(struct fdwatch_s *fw); + +#endif /* __NETUTILS_THTTPD_FDWATCH_H */ + diff --git a/apps/netutils/thttpd/libhttpd.c b/apps/netutils/thttpd/libhttpd.c new file mode 100644 index 000000000..05831b335 --- /dev/null +++ b/apps/netutils/thttpd/libhttpd.c @@ -0,0 +1,3525 @@ +/**************************************************************************** + * netutils/thttpd/libhttpd.c + * HTTP Protocol Library + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> +#include <fcntl.h> +#include <dirent.h> +#include <signal.h> +#include <sched.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/regex.h> +#include <apps/netutils/thttpd.h> + +#include "config.h" +#include "libhttpd.h" +#include "thttpd_alloc.h" +#include "thttpd_strings.h" +#include "thttpd_cgi.h" +#include "timers.h" +#include "tdate_parse.h" +#include "fdwatch.h" + +#ifdef CONFIG_THTTPD + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +#define NAMLEN(dirent) strlen((dirent)->d_name) + +extern char *crypt(const char *key, const char *setting); + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* Conditional macro to allow two alternate forms for use in the built-in + * error pages. If EXPLICIT_ERROR_PAGES is defined, the second and more + * explicit error form is used; otherwise, the first and more generic + * form is used. + */ + +#ifdef EXPLICIT_ERROR_PAGES +# define ERROR_FORM(a,b) b +#else +# define ERROR_FORM(a,b) a +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void free_httpd_server(httpd_server *hs); +static int initialize_listen_socket(httpd_sockaddr *saP); +static void add_response(httpd_conn *hc, const char *str); +static void send_mime(httpd_conn *hc, int status, const char *title, const char *encodings, + const char *extraheads, const char *type, off_t length, time_t mod); +static void send_response(httpd_conn *hc, int status, const char *title, + const char *extraheads, const char *form, const char *arg); +static void send_response_tail(httpd_conn *hc); +static void defang(const char *str, char *dfstr, int dfsize); +#ifdef CONFIG_THTTPD_ERROR_DIRECTORY +static int send_err_file(httpd_conn *hc, int status, char *title, + char *extraheads, char *filename); +#endif +#ifdef CONFIG_THTTPD_AUTH_FILE +static void send_authenticate(httpd_conn *hc, char *realm); +static int b64_decode(const char *str, unsigned char *space, int size); +static int auth_check(httpd_conn *hc, char *dirname); +static int auth_check2(httpd_conn *hc, char *dirname); +#endif +static void send_dirredirect(httpd_conn *hc); +#ifdef CONFIG_THTTPD_TILDE_MAP1 +static int httpd_tilde_map1(httpd_conn *hc); +#endif +#ifdef CONFIG_THTTPD_TILDE_MAP2 +static int httpd_tilde_map2(httpd_conn *hc); +#endif +#ifdef CONFIG_THTTPD_VHOST +static int vhost_map(httpd_conn *hc); +#endif +static char *expand_filename(char *path, char **restP, bool tildemapped); +static char *bufgets(httpd_conn *hc); +static void de_dotdot(char *file); +static void init_mime(void); +static void figure_mime(httpd_conn *hc); +#ifdef CONFIG_THTTPD_GENERATE_INDICES +static void ls_child(int argc, char **argv); +static int ls(httpd_conn *hc); +#endif +#ifdef SERVER_NAME_LIST +static char *hostname_map(char *hostname); +#endif + +static int check_referer(httpd_conn *hc); +#ifdef CONFIG_THTTPD_URLPATTERN +static int really_check_referer(httpd_conn *hc); +#endif +#ifdef CONFIG_DEBUG +static int sockaddr_check(httpd_sockaddr *saP); +#else +# define sockaddr_check(saP) (1) +#endif +static size_t sockaddr_len(httpd_sockaddr *saP); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This global keeps track of whether we are in the main task or a + * sub-task. The reason is that httpd_write_response() can get called + * in either context; when it is called from the main task it must use + * non-blocking I/O to avoid stalling the server, but when it is called + * from a sub-task it wants to use blocking I/O so that the whole + * response definitely gets written. So, it checks this variable. A bit + * of a hack but it seems to do the right thing. + */ + +static pid_t main_thread; + +/* Include MIME encodings and types */ + +#include "mime_types.h" + +/* Names for index file */ + +static const char *index_names[] = { CONFIG_THTTPD_INDEX_NAMES }; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void free_httpd_server(httpd_server * hs) +{ + if (hs) + { + if (hs->hostname) + { + httpd_free(hs->hostname); + } + + httpd_free(hs); + } +} + +static int initialize_listen_socket(httpd_sockaddr *saP) +{ + int listen_fd; + int on; + int flags; + + /* Check sockaddr. */ + +#ifdef CONFIG_DEBUG + if (!sockaddr_check(saP)) + { + ndbg("unknown sockaddr family on listen socket\n"); + return -1; + } +#endif + + /* Create socket. */ + + nvdbg("Create listen socket\n"); + listen_fd = socket(saP->sin_family, SOCK_STREAM, 0); + if (listen_fd < 0) + { + ndbg("socket failed: %d\n", errno); + return -1; + } + + /* Allow reuse of local addresses. */ + + on = 1; + if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) + { + ndbg("setsockopt(SO_REUSEADDR) failed: %d\n", errno); + } + + /* Bind to it. */ + + if (bind(listen_fd, (struct sockaddr*)saP, sockaddr_len(saP)) < 0) + { + ndbg("bind to %s failed: %d\n", httpd_ntoa(saP), errno); + (void)close(listen_fd); + return -1; + } + + /* Set the listen file descriptor to no-delay / non-blocking mode. */ + + flags = fcntl(listen_fd, F_GETFL, 0); + if (flags == -1) + { + ndbg("fcntl(F_GETFL) failed: %d\n", errno); + (void)close(listen_fd); + return -1; + } + + if (fcntl(listen_fd, F_SETFL, flags | O_NDELAY) < 0) + { + ndbg("fcntl(O_NDELAY) failed: %d\n", errno); + (void)close(listen_fd); + return -1; + } + + /* Start a listen going. */ + + if (listen(listen_fd, CONFIG_THTTPD_LISTEN_BACKLOG) < 0) + { + ndbg("listen failed: %d\n", errno); + (void)close(listen_fd); + return -1; + } + + return listen_fd; +} + +/* Append a string to the buffer waiting to be sent as response. */ + +static void add_response(httpd_conn *hc, const char *str) +{ + int resplen; + int len; + + len = strlen(str); + resplen = hc->buflen + len; + + if (resplen > CONFIG_THTTPD_IOBUFFERSIZE) + { + ndbg("resplen(%d) > buffer size(%d)\n", resplen, CONFIG_THTTPD_IOBUFFERSIZE); + resplen = CONFIG_THTTPD_IOBUFFERSIZE; + len = resplen - hc->buflen; + } + + memcpy(&(hc->buffer[hc->buflen]), str, len); + hc->buflen = resplen; +} + +static void send_mime(httpd_conn *hc, int status, const char *title, const char *encodings, + const char *extraheads, const char *type, off_t length, time_t mod) +{ + struct timeval now; + const char *rfc1123fmt = "%a, %d %b %Y %H:%M:%S GMT"; + char tmbuf[72]; +#ifdef CONFIG_THTTPD_MAXAGE + time_t expires; + char expbuf[72]; +#endif + char fixed_type[72]; + char buf[128]; + int partial_content; + int s100; + + hc->bytes_to_send = length; + if (hc->mime_flag) + { + if (status == 200 && hc->got_range && + (hc->range_end >= hc->range_start) && + ((hc->range_end != length - 1) || + (hc->range_start != 0)) && + (hc->range_if == (time_t) - 1 || hc->range_if == hc->sb.st_mtime)) + { + partial_content = 1; + status = 206; + title = ok206title; + } + else + { + partial_content = 0; + hc->got_range = false; + } + + gettimeofday(&now, NULL); + if (mod == (time_t)0) + { + mod = now.tv_sec; + } + + (void)snprintf(fixed_type, sizeof(fixed_type), type, CONFIG_THTTPD_CHARSET); + (void)snprintf(buf, sizeof(buf), "%.20s %d %s\r\n", hc->protocol, status, title); + add_response(hc, buf); + (void)snprintf(buf, sizeof(buf), "Server: %s\r\n", "thttpd"); + add_response(hc, buf); + (void)snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", fixed_type); + add_response(hc, buf); + (void)strftime(tmbuf, sizeof(tmbuf), rfc1123fmt, gmtime(&now.tv_sec)); + (void)snprintf(buf, sizeof(buf), "Date: %s\r\n", tmbuf); + add_response(hc, buf); + (void)strftime(tmbuf, sizeof(tmbuf), rfc1123fmt, gmtime(&mod)); + (void)snprintf(buf, sizeof(buf), "Last-Modified: %s\r\n", tmbuf); + add_response(hc, buf); + add_response(hc, "Accept-Ranges: bytes\r\n"); + add_response(hc, "Connection: close\r\n"); + + s100 = status / 100; + if (s100 != 2 && s100 != 3) + { + (void)snprintf(buf, sizeof(buf), "Cache-Control: no-cache,no-store\r\n"); + add_response(hc, buf); + } + + if (encodings[0] != '\0') + { + (void)snprintf(buf, sizeof(buf), "Content-Encoding: %s\r\n", encodings); + add_response(hc, buf); + } + + if (partial_content) + { + (void)snprintf(buf, sizeof(buf),"Content-Range: bytes %ld-%ld/%ld\r\n", + (long)hc->range_start, (long)hc->range_end, (long)length); + add_response(hc, buf); + (void)snprintf(buf, sizeof(buf),"Content-Length: %ld\r\n", + (long)(hc->range_end - hc->range_start + 1)); + add_response(hc, buf); + } + else if (length >= 0) + { + (void)snprintf(buf, sizeof(buf), "Content-Length: %ld\r\n", (long)length); + add_response(hc, buf); + } + +#ifdef CONFIG_THTTPD_P3P + (void)snprintf(buf, sizeof(buf), "P3P: %s\r\n", CONFIG_THTTPD_P3P); + add_response(hc, buf); +#endif + +#ifdef CONFIG_THTTPD_MAXAGE + expires = now + CONFIG_THTTPD_MAXAGE; + (void)strftime(expbuf, sizeof(expbuf), rfc1123fmt, gmtime(&expires)); + (void)snprintf(buf, sizeof(buf), + "Cache-Control: max-age=%d\r\nExpires: %s\r\n", + CONFIG_THTTPD_MAXAGE, expbuf); + add_response(hc, buf); +#endif + + if (extraheads[0] != '\0') + { + add_response(hc, extraheads); + } + add_response(hc, "\r\n"); + } +} + +static void send_response(httpd_conn *hc, int status, const char *title, const char *extraheads, + const char *form, const char *arg) +{ + char defanged[72]; + char buf[128]; + + nvdbg("title: \"%s\" form: \"%s\"\n", title, form); + + send_mime(hc, status, title, "", extraheads, "text/html; charset=%s", (off_t)-1, (time_t)0); + add_response(hc, html_html); + add_response(hc, html_hdtitle); + (void)snprintf(buf, sizeof(buf), "%d %s", status, title); + add_response(hc, buf); + add_response(hc, html_titlehd); + add_response(hc, html_body); + add_response(hc, html_hdr2); + add_response(hc, buf); + add_response(hc, html_endhdr2); + + defang(arg, defanged, sizeof(defanged)); + (void)snprintf(buf, sizeof(buf), form, defanged); + add_response(hc, buf); + + if (match("**MSIE**", hc->useragent)) + { + int n; + add_response(hc, "<!--\n"); + for (n = 0; n < 6; ++n) + add_response(hc, + "Padding so that MSIE deigns to show this error instead of its own canned one.\n"); + add_response(hc, "-->\n"); + } + + send_response_tail(hc); +} + +static void send_response_tail(httpd_conn *hc) +{ + add_response(hc, "<HR>\r\n<ADDRESS><A HREF=\""); + add_response(hc, CONFIG_THTTPD_SERVER_ADDRESS); + add_response(hc, "\">"); + add_response(hc, "thttpd"); + add_response(hc, "</A></ADDRESS>\r\n"); + add_response(hc, html_endbody); + add_response(hc, html_endhtml); +} + +static void defang(const char *str, char *dfstr, int dfsize) +{ + const char *cp1; + char *cp2; + + for (cp1 = str, cp2 = dfstr; + *cp1 != '\0' && cp2 - dfstr < dfsize - 5; ++cp1, ++cp2) + { + switch (*cp1) + { + case '<': + *cp2++ = '&'; + *cp2++ = 'l'; + *cp2++ = 't'; + *cp2 = ';'; + break; + case '>': + *cp2++ = '&'; + *cp2++ = 'g'; + *cp2++ = 't'; + *cp2 = ';'; + break; + default: + *cp2 = *cp1; + break; + } + } + *cp2 = '\0'; +} + +#ifdef CONFIG_THTTPD_ERROR_DIRECTORY +static int send_err_file(httpd_conn *hc, int status, char *title, char *extraheads, + char *filename) +{ + FILE *fp; + char buf[1000]; + size_t nread; + + fp = fopen(filename, "r"); + if (fp == NULL) + { + return 0; + } + + send_mime(hc, status, title, "", extraheads, "text/html; charset=%s", + (off_t)-1, (time_t)0); + for (;;) + { + nread = fread(buf, 1, sizeof(buf) - 1, fp); + if (nread == 0) + break; + buf[nread] = '\0'; + add_response(hc, buf); + } + (void)fclose(fp); + +#ifdef ERR_APPEND_SERVER_INFO + send_response_tail(hc); +#endif + + return 1; +} +#endif + +#ifdef CONFIG_THTTPD_AUTH_FILE +static void send_authenticate(httpd_conn *hc, char *realm) +{ + static char *header; + static size_t maxheader = 0; + static char headstr[] = "WWW-Authenticate: Basic realm=\""; + + httpd_realloc_str(&header, &maxheader, sizeof(headstr) + strlen(realm) + 3); + (void)snprintf(header, maxheader, "%s%s\"\r\n", headstr, realm); + httpd_send_err(hc, 401, err401title, header, err401form, hc->encodedurl); + + /* If the request was a POST then there might still be data to be read, so + * we need to do a lingering close. + */ + + if (hc->method == METHOD_POST) + { + hc->should_linger = true; + } +} + +/* Base-64 decoding. This represents binary data as printable ASCII + * characters. Three 8-bit binary bytes are turned into four 6-bit + * values, like so: + * + * [11111111][22222222][33333333] -> [111111][112222][222233][333333] + * + * Then the 6-bit values are represented using the characters "A-Za-z0-9+/". + */ + +static inline b64_charmap(char *ch) +{ + char bin6; + + bin6 = -1; + if (c == 0x20) /* ' ' */ + { + bin6 = 62; /* ' ' maps to 62 */ + } + elseif (c == 0x2f) /* '/' */ + { + bin6 = 63; /* '/' maps to 63 */ + } + else if (c >= 0x30) /* '0' */ + { + else if (c <= 0x39) /* '9' */ + { + bin6 = (c - 0x39 + 52); /* '0'-'9' maps to 52-61 */ + } + else if (c >= 0x41) /* 'A' */ + { + if (c <= 0x5a) /* 'Z' */ + { + bin6 = c - 0x41; /* 'A'-'Z' map to 0 - 25 */ + } + else if (c >= 0x61) /* 'a' */ + { + if (c <= 0x7a) /* 'z' */ + { + bin6 = c - 0x61 + 26; /* 'a'-'z' map to 0 - 25 */ + } + } + } + } + +} + +/* Do base-64 decoding on a string. Ignore any non-base64 bytes. + * Return the actual number of bytes generated. The decoded size will + * be at most 3/4 the size of the encoded, and may be smaller if there + * are padding characters (blanks, newlines). + */ + +static int b64_decode(const char *str, unsigned char *space, int size) +{ + const char *cp; + int ndx; + int phase; + int decoded; + int prev_decoded = 0; + unsigned char packed; + + ndx = 0; + phase = 0; + for (cp = str; *cp != '\0', ndx < size; cp++) + { + /* Decode base-64 */ + + decoded = b64_charmap(*cp); /* Decode ASCII representations to 6-bit binary */ + if (decoded != -1) + { + switch (phase) + { + case 0: + phase = 1; + break; + + case 1: + space[ndx++] = ((prev_decoded << 2) | ((decoded & 0x30) >> 4)); + phase = 2; + break; + + case 2: + space[ndx++] =(((prev_decoded & 0xf) << 4) | ((decoded & 0x3packed) >> 2)); + phase = 3; + break; + + case 3: + space[ndx++] =(((prev_decoded & 0x03) << 6) | decoded); + phase = 0; + break; + } + prev_decoded = decoded; + } + } + return ndx; +} + +/* Returns -1 == unauthorized, 0 == no auth file, 1 = authorized. */ + +static int auth_check(httpd_conn *hc, char *dirname) +{ +#ifdef CONFIG_THTTPD_GLOBALPASSWD + char *topdir; + +#ifdef CONFIG_THTTPD_VHOST + if (hc->hostdir[0] != '\0') + { + topdir = hc->hostdir; + } + else +#endif + { + topdir = httpd_root; + } + + switch (auth_check2(hc, topdir)) + { + case -1: + return -1; + case 1: + return 1; + } +#endif + return auth_check2(hc, dirname); +} + +/* Returns -1 == unauthorized, 0 == no auth file, 1 = authorized. */ + +static int auth_check2(httpd_conn *hc, char *dirname) +{ + static char *authpath; + static size_t maxauthpath = 0; + struct stat sb; + char authinfo[500]; + char *authpass; + char *colon; + int l; + FILE *fp; + char line[500]; + char *cryp; + static char *prevauthpath; + static size_t maxprevauthpath = 0; + static time_t prevmtime; + static char *prevuser; + static size_t maxprevuser = 0; + static char *prevcryp; + static size_t maxprevcryp = 0; + + /* Construct auth filename. */ + + httpd_realloc_str(&authpath, &maxauthpath, + strlen(dirname) + 1 + sizeof(CONFIG_THTTPD_AUTH_FILE)); + (void)snprintf(authpath, maxauthpath, "%s/%s", dirname, CONFIG_THTTPD_AUTH_FILE); + + /* Does this directory have an auth file? */ + + if (stat(authpath, &sb) < 0) + { + /* Nope, let the request go through. */ + + return 0; + } + + /* Does this request contain basic authorization info? */ + + if (hc->authorization[0] == '\0' || strncmp(hc->authorization, "Basic ", 6) != 0) + { + /* Nope, return a 401 Unauthorized. */ + + send_authenticate(hc, dirname); + return -1; + } + + /* Decode it. */ + + l = b64_decode(&(hc->authorization[6]), (unsigned char *)authinfo, sizeof(authinfo) - 1); + authinfo[l] = '\0'; + + /* Split into user and password. */ + + authpass = strchr(authinfo, ':'); + if (!authpass) + { + /* No colon? Bogus auth info. */ + + send_authenticate(hc, dirname); + return -1; + } + *authpass++ = '\0'; + + /* If there are more fields, cut them off. */ + + colon = strchr(authpass, ':'); + if (colon) + { + *colon = '\0'; + } + + /* See if we have a cached entry and can use it. */ + + if (maxprevauthpath != 0 && + strcmp(authpath, prevauthpath) == 0 && + sb.st_mtime == prevmtime && strcmp(authinfo, prevuser) == 0) + { + /* Yes. Check against the cached encrypted password. */ + + if (strcmp(crypt(authpass, prevcryp), prevcryp) == 0) + { + /* Ok! */ + + httpd_realloc_str(&hc->remoteuser, &hc->maxremoteuser, + strlen(authinfo)); + (void)strcpy(hc->remoteuser, authinfo); + return 1; + } + else + { + /* No. */ + + send_authenticate(hc, dirname); + return -1; + } + } + + /* Open the password file. */ + + fp = fopen(authpath, "r"); + if (fp == NULL) + { + /* The file exists but we can't open it? Disallow access. */ + + ndbg("%s auth file %s could not be opened: %d\n", + httpd_ntoa(&hc->client_addr), authpath, errno); + + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' is protected by an authentication file, " + "but the authentication file cannot be opened.\n"), + hc->encodedurl); + return -1; + } + + /* Read it. */ + + while (fgets(line, sizeof(line), fp) != NULL) + { + /* Nuke newline. */ + + l = strlen(line); + if (line[l - 1] == '\n') + { + line[l - 1] = '\0'; + } + + /* Split into user and encrypted password. */ + + cryp = strchr(line, ':'); + if (!cryp) + { + continue; + } + *cryp++ = '\0'; + + /* Is this the right user? */ + + if (strcmp(line, authinfo) == 0) + { + /* Yes. */ + + (void)fclose(fp); + + /* So is the password right? */ + + if (strcmp(crypt(authpass, cryp), cryp) == 0) + { + /* Ok! */ + + httpd_realloc_str(&hc->remoteuser, &hc->maxremoteuser, strlen(line)); + (void)strcpy(hc->remoteuser, line); + + /* And cache this user's info for next time. */ + + httpd_realloc_str(&prevauthpath, &maxprevauthpath, strlen(authpath)); + (void)strcpy(prevauthpath, authpath); + prevmtime = sb.st_mtime; + httpd_realloc_str(&prevuser, &maxprevuser, strlen(authinfo)); + (void)strcpy(prevuser, authinfo); + httpd_realloc_str(&prevcryp, &maxprevcryp, strlen(cryp)); + (void)strcpy(prevcryp, cryp); + return 1; + } + else + { + /* No. */ + + send_authenticate(hc, dirname); + return -1; + } + } + } + + /* Didn't find that user. Access denied. */ + + (void)fclose(fp); + send_authenticate(hc, dirname); + return -1; +} +#endif /* CONFIG_THTTPD_AUTH_FILE */ + +static void send_dirredirect(httpd_conn *hc) +{ + static char *location; + static char *header; + static size_t maxlocation = 0; + static size_t maxheader = 0; + static char headstr[] = "Location: "; + + if (hc->query[0] != '\0') + { + char *cp = strchr(hc->encodedurl, '?'); + if (cp) + { + *cp = '\0'; + } + + httpd_realloc_str(&location, &maxlocation, strlen(hc->encodedurl) + 2 + strlen(hc->query)); + (void)snprintf(location, maxlocation, "%s/?%s", hc->encodedurl, hc->query); + } + else + { + httpd_realloc_str(&location, &maxlocation, strlen(hc->encodedurl) + 1); + (void)snprintf(location, maxlocation, "%s/", hc->encodedurl); + } + + httpd_realloc_str(&header, &maxheader, sizeof(headstr) + strlen(location)); + (void)snprintf(header, maxheader, "%s%s\r\n", headstr, location); + send_response(hc, 302, err302title, header, err302form, location); +} + +/* Map a ~username/whatever URL into <prefix>/username. */ + +#ifdef CONFIG_THTTPD_TILDE_MAP1 +static int httpd_tilde_map1(httpd_conn *hc) +{ + static char *temp; + static size_t maxtemp = 0; + int len; + static char *prefix = CONFIG_THTTPD_TILDE_MAP1; + + len = strlen(hc->expnfilename) - 1; + httpd_realloc_str(&temp, &maxtemp, len); + (void)strcpy(temp, &hc->expnfilename[1]); + + httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, strlen(prefix) + 1 + len); + (void)strcpy(hc->expnfilename, prefix); + + if (prefix[0] != '\0') + { + (void)strcat(hc->expnfilename, "/"); + } + + (void)strcat(hc->expnfilename, temp); + return 1; +} +#endif + +/* Map a ~username/whatever URL into <user's homedir>/<postfix>. */ + +#ifdef CONFIG_THTTPD_TILDE_MAP2 +static int httpd_tilde_map2(httpd_conn *hc) +{ + static char *temp; + static size_t maxtemp = 0; + static char *postfix = CONFIG_THTTPD_TILDE_MAP2; + char *cp; + struct passwd *pw; + char *alt; + char *rest; + + /* Get the username. */ + + httpd_realloc_str(&temp, &maxtemp, strlen(hc->expnfilename) - 1); + (void)strcpy(temp, &hc->expnfilename[1]); + + cp = strchr(temp, '/'); + if (cp) + { + *cp++ = '\0'; + } + else + { + cp = ""; + } + + /* Get the passwd entry. */ + + pw = getpwnam(temp); + if (!pw) + { + return 0; + } + + /* Set up altdir. */ + + httpd_realloc_str(&hc->altdir, &hc->maxaltdir, strlen(pw->pw_dir) + 1 + strlen(postfix)); + (void)strcpy(hc->altdir, pw->pw_dir); + if (postfix[0] != '\0') + { + (void)strcat(hc->altdir, "/"); + (void)strcat(hc->altdir, postfix); + } + + alt = expand_filename(hc->altdir, &rest, true); + if (rest[0] != '\0') + { + return 0; + } + + httpd_realloc_str(&hc->altdir, &hc->maxaltdir, strlen(alt)); + (void)strcpy(hc->altdir, alt); + + /* And the filename becomes altdir plus the post-~ part of the original. */ + + httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, strlen(hc->altdir) + 1 + strlen(cp)); + (void)snprintf(hc->expnfilename, hc->maxexpnfilename, "%s/%s", hc->altdir, cp); + + /* For this type of tilde mapping, we want to defeat vhost mapping. */ + + hc->tildemapped = true; + return 1; +} +#endif + +/* Virtual host mapping. */ + +#ifdef CONFIG_THTTPD_VHOST +static int vhost_map(httpd_conn *hc) +{ + httpd_sockaddr sa; + socklen_t sz; + static char *tempfilename; + static size_t maxtempfilename = 0; + char *cp1; + int len; +#ifdef VHOST_DIRLEVELS + int i; + char *cp2; +#endif + + /* Figure out the virtual hostname. */ + + if (hc->reqhost[0] != '\0') + { + hc->vhostname = hc->reqhost; + } + else if (hc->hdrhost[0] != '\0') + { + hc->vhostname = hc->hdrhost; + } + else + { + sz = sizeof(sa); + if (getsockname(hc->conn_fd, &sa.sa, &sz) < 0) + { + ndbg("getsockname: %d\n", errno); + return 0; + } + hc->vhostname = httpd_ntoa(&sa); + } + + /* Pound it to lower case. */ + + for (cp1 = hc->vhostname; *cp1 != '\0'; ++cp1) + { + if (isupper(*cp1)) + { + *cp1 = tolower(*cp1); + } + } + + if (hc->tildemapped) + { + return 1; + } + + /* Figure out the host directory. */ + +#ifdef VHOST_DIRLEVELS + httpd_realloc_str(&hc->hostdir, &hc->maxhostdir, strlen(hc->vhostname) + 2 * VHOST_DIRLEVELS); + if (strncmp(hc->vhostname, "www.", 4) == 0) + { + cp1 = &hc->vhostname[4]; + } + else + { + cp1 = hc->vhostname; + } + + for (cp2 = hc->hostdir, i = 0; i < VHOST_DIRLEVELS; ++i) + { + /* Skip dots in the hostname. If we don't, then we get vhost + * directories in higher level of filestructure if dot gets involved + * into path construction. It's `while' used here instead of `if' for + * it's possible to have a hostname formed with two dots at the end of + * it. + */ + + while (*cp1 == '.') + { + ++cp1; + } + + /* Copy a character from the hostname, or '_' if we ran out. */ + + if (*cp1 != '\0') + { + *cp2++ = *cp1++; + } + else + { + *cp2++ = '_'; + } + + /* Copy a slash. */ + + *cp2++ = '/'; + } + (void)strcpy(cp2, hc->vhostname); +#else /* VHOST_DIRLEVELS */ + httpd_realloc_str(&hc->hostdir, &hc->maxhostdir, strlen(hc->vhostname)); + (void)strcpy(hc->hostdir, hc->vhostname); +#endif /* VHOST_DIRLEVELS */ + + /* Prepend hostdir to the filename. */ + + len = strlen(hc->expnfilename); + httpd_realloc_str(&tempfilename, &maxtempfilename, len); + (void)strcpy(tempfilename, hc->expnfilename); + httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, strlen(hc->hostdir) + 1 + len); + (void)strcpy(hc->expnfilename, hc->hostdir); + (void)strcat(hc->expnfilename, "/"); + (void)strcat(hc->expnfilename, tempfilename); + return 1; +} +#endif + +/* Expands filename, deleting ..'s and leading /'s. + * Returns the expanded path (pointer to static string), or NULL on + * errors. Also returns, in the string pointed to by restP, any trailing + * parts of the path that don't exist. + */ + +static char *expand_filename(char *path, char **restP, bool tildemapped) +{ + static char *checked; + static char *rest; + static size_t maxchecked = 0, maxrest = 0; + size_t checkedlen, restlen, prevcheckedlen, prevrestlen; +#if 0 // REVISIT + struct stat sb; +#endif + int nlinks, i; + char *r; + char *cp1; + char *cp2; + + nvdbg("path: \"%s\"\n", path); +#if 0 // REVISIT + /* We need to do the pathinfo check. we do a single stat() of the whole + * filename - if it exists, then we return it as is with nothing in restP. + * If it doesn't exist, we fall through to the existing code. + */ + + if (stat(path, &sb) != -1) + { + checkedlen = strlen(path); + httpd_realloc_str(&checked, &maxchecked, checkedlen); + (void)strcpy(checked, path); + + /* Trim trailing slashes. */ + + while (checked[checkedlen - 1] == '/') + { + checked[checkedlen - 1] = '\0'; + --checkedlen; + } + + httpd_realloc_str(&rest, &maxrest, 0); + rest[0] = '\0'; + *restP = rest; + return checked; + } +#endif + + /* Handle leading / or . and relative pathes by copying the default directory into checked */ + + if ((path[0] == '/' && strncmp(path, httpd_root, strlen(httpd_root)) != 0) || path[0] != '/') + { + /* Start out with httpd_root in checked. Allow space in the reallocation + * include NULL terminator and possibly a '/' + */ + + checkedlen = strlen(httpd_root); + httpd_realloc_str(&checked, &maxchecked, checkedlen+2); + strcpy(checked, httpd_root); + + /* Skip over leading '.' */ + + if (path[0] == '.') + { + path++; + } + + /* Add '/' to separate relative pathes */ + + else if (path[0] != '/') + { + checked[checkedlen] = '/'; + checked[checkedlen+1] = '\0'; + } + } + else + { + /* Start out with nothing in checked */ + + httpd_realloc_str(&checked, &maxchecked, 1); + checked[0] = '\0'; + checkedlen = 0; + } + + /* Copy the whole filename (minus the leading '.') into rest. */ + + restlen = strlen(path); + httpd_realloc_str(&rest, &maxrest, restlen+1); + (void)strcpy(rest, path); + + /* trim trailing slash */ + + if (rest[restlen - 1] == '/') + { + rest[--restlen] = '\0'; + } + + r = rest; + nlinks = 0; + + /* While there are still components to check... */ + + while (restlen > 0) + { + /* Save current checkedlen. Save current restlen in case we get a non-existant component. */ + + prevcheckedlen = checkedlen; + prevrestlen = restlen; + + /* Grab one component from r and transfer it to checked. */ + + cp1 = strchr(r, '/'); + if (cp1) + { + i = cp1 - r; + if (i == 0) + { + /* Special case for absolute paths. */ + + httpd_realloc_str(&checked, &maxchecked, checkedlen + 1); + (void)strncpy(&checked[checkedlen], r, 1); + checkedlen += 1; + } + else if (strncmp(r, "..", MAX(i, 2)) == 0) + { + /* Ignore ..'s that go above the start of the path. */ + + if (checkedlen != 0) + { + cp2 = strrchr(checked, '/'); + if (!cp2) + { + checkedlen = 0; + } + else if (cp2 == checked) + { + checkedlen = 1; + } + else + { + checkedlen = cp2 - checked; + } + } + } + else + { + httpd_realloc_str(&checked, &maxchecked, checkedlen + 1 + i); + if (checkedlen > 0 && checked[checkedlen - 1] != '/') + { + checked[checkedlen++] = '/'; + } + + (void)strncpy(&checked[checkedlen], r, i); + checkedlen += i; + } + + checked[checkedlen] = '\0'; + r += i + 1; + restlen -= i + 1; + } + else + { + /* No slashes remaining, r is all one component. */ + + if (strcmp(r, "..") == 0) + { + /* Ignore ..'s that go above the start of the path. */ + + if (checkedlen != 0) + { + cp2 = strrchr(checked, '/'); + if (!cp2) + { + checkedlen = 0; + } + else if (cp2 == checked) + { + checkedlen = 1; + } + else + { + checkedlen = cp2 - checked; + } + + checked[checkedlen] = '\0'; + } + } + else + { + httpd_realloc_str(&checked, &maxchecked, checkedlen + 1 + restlen); + if (checkedlen > 0 && checked[checkedlen - 1] != '/') + { + checked[checkedlen++] = '/'; + } + + (void)strcpy(&checked[checkedlen], r); + checkedlen += restlen; + } + + r += restlen; + restlen = 0; + } + } + + /* Ok. */ + + *restP = r; + if (checked[0] == '\0') + { + (void)strcpy(checked, httpd_root); + } + + nvdbg("checked: \"%s\"\n", checked); + return checked; +} + +static char *bufgets(httpd_conn *hc) +{ + int i; + char c; + + for (i = hc->checked_idx; hc->checked_idx < hc->read_idx; ++hc->checked_idx) + { + c = hc->read_buf[hc->checked_idx]; + if (c == '\012' || c == '\015') + { + hc->read_buf[hc->checked_idx] = '\0'; + ++hc->checked_idx; + if (c == '\015' && hc->checked_idx < hc->read_idx && + hc->read_buf[hc->checked_idx] == '\012') + { + hc->read_buf[hc->checked_idx] = '\0'; + ++hc->checked_idx; + } + return &(hc->read_buf[i]); + } + } + return NULL; +} + +static void de_dotdot(char *file) +{ + char *cp; + char *cp2; + int l; + + /* Collapse any multiple / sequences. */ + + while ((cp = strstr(file, "//")) != NULL) + { + for (cp2 = cp + 2; *cp2 == '/'; ++cp2) + { + continue; + } + + (void)strcpy(cp + 1, cp2); + } + + /* Remove leading ./ and any /./ sequences. */ + + while (strncmp(file, "./", 2) == 0) + { + (void)strcpy(file, file + 2); + } + + while ((cp = strstr(file, "/./")) != NULL) + { + (void)strcpy(cp, cp + 2); + } + + /* Alternate between removing leading ../ and removing xxx/../ */ + + for (;;) + { + while (strncmp(file, "../", 3) == 0) + { + (void)strcpy(file, file + 3); + } + + cp = strstr(file, "/../"); + if (!cp) + { + break; + } + + for (cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2) + { + continue; + } + + (void)strcpy(cp2 + 1, cp + 4); + } + + /* Also elide any xxx/.. at the end. */ + + while ((l = strlen(file)) > 3 && strcmp((cp = file + l - 3), "/..") == 0) + { + for (cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2) + { + continue; + } + + if (cp2 < file) + { + break; + } + + *cp2 = '\0'; + } +} + +static void init_mime(void) +{ + int i; + + /* Fill in the lengths. */ + + for (i = 0; i < n_enc_tab; ++i) + { + enc_tab[i].ext_len = strlen(enc_tab[i].ext); + enc_tab[i].val_len = strlen(enc_tab[i].val); + } + + for (i = 0; i < n_typ_tab; ++i) + { + typ_tab[i].ext_len = strlen(typ_tab[i].ext); + typ_tab[i].val_len = strlen(typ_tab[i].val); + } +} + +/* Figure out MIME encodings and type based on the filename. Multiple + * encodings are separated by commas, and are listed in the order in + * which they were applied to the file. + */ + +static void figure_mime(httpd_conn *hc) +{ + char *prev_dot; + char *dot; + char *ext; + int me_indexes[100], n_me_indexes; + size_t ext_len, encodings_len; + int i, top, bot, mid; + int r; + char *default_type = "text/plain; charset=%s"; + + /* Peel off encoding extensions until there aren't any more. */ + + n_me_indexes = 0; + for (prev_dot = &hc->expnfilename[strlen(hc->expnfilename)];; prev_dot = dot) + { + for (dot = prev_dot - 1; dot >= hc->expnfilename && *dot != '.'; --dot) + ; + + if (dot < hc->expnfilename) + { + /* No dot found. No more encoding extensions, and no type + * extension either. + */ + + hc->type = default_type; + goto done; + } + + ext = dot + 1; + ext_len = prev_dot - ext; + + /* Search the encodings table. Linear search is fine here, there are + * only a few entries. + */ + + for (i = 0; i < n_enc_tab; ++i) + { + if (ext_len == enc_tab[i].ext_len && + strncasecmp(ext, enc_tab[i].ext, ext_len) == 0) + { + if (n_me_indexes < sizeof(me_indexes) / sizeof(*me_indexes)) + { + me_indexes[n_me_indexes] = i; + ++n_me_indexes; + } + goto next; + } + } + + /* No encoding extension found. Break and look for a type extension. */ + + break; + + next:; + } + + /* Binary search for a matching type extension. */ + + top = n_typ_tab - 1; + bot = 0; + while (top >= bot) + { + mid = (top + bot) / 2; + r = strncasecmp(ext, typ_tab[mid].ext, ext_len); + if (r < 0) + { + top = mid - 1; + } + else if (r > 0) + { + bot = mid + 1; + } + else if (ext_len < typ_tab[mid].ext_len) + { + top = mid - 1; + } + else if (ext_len > typ_tab[mid].ext_len) + { + bot = mid + 1; + } + else + { + hc->type = typ_tab[mid].val; + goto done; + } + } + hc->type = default_type; + +done: + + /* The last thing we do is actually generate the mime-encoding header. */ + + hc->encodings[0] = '\0'; + encodings_len = 0; + for (i = n_me_indexes - 1; i >= 0; --i) + { + httpd_realloc_str(&hc->encodings, &hc->maxencodings, + encodings_len + enc_tab[me_indexes[i]].val_len + 1); + if (hc->encodings[0] != '\0') + { + (void)strcpy(&hc->encodings[encodings_len], ","); + ++encodings_len; + } + + (void)strcpy(&hc->encodings[encodings_len], enc_tab[me_indexes[i]].val); + encodings_len += enc_tab[me_indexes[i]].val_len; + } +} + +/* qsort comparison routine. */ + +#ifdef CONFIG_THTTPD_GENERATE_INDICES +static int name_compare(char **a, char **b) +{ + return strcmp(*a, *b); +} + +static void ls_child(int argc, char **argv) +{ + FAR httpd_conn *hc = (FAR httpd_conn*)strtoul(argv[1], NULL, 16); + DIR *dirp; + struct dirent *de; + int namlen; + static int maxnames = 0; + int nnames; + static char *names; + static char **nameptrs; + static char *name; + static size_t maxname = 0; + static char *rname; + static size_t maxrname = 0; + static char *encrname; + static size_t maxencrname = 0; + FILE *fp; + int i, r; + struct stat sb; + struct stat lsb; + char modestr[20]; + char *linkprefix; + char link[MAXPATHLEN + 1]; + char *fileclass; + time_t now; + char *timestr; + ClientData client_data; + + httpd_unlisten(hc->hs); + send_mime(hc, 200, ok200title, "", "", "text/html; charset=%s", + (off_t) - 1, hc->sb.st_mtime); + httpd_write_response(hc); + + /* Open a stdio stream so that we can use fprintf, which is more + * efficient than a bunch of separate write()s. We don't have to + * worry about double closes or file descriptor leaks cause we're + * in a sub-task. + */ + + fp = fdopen(hc->conn_fd, "w"); + if (fp == NULL) + { + ndbg("fdopen: %d\n", errno); + INTERNALERROR("fdopen"); + httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); + httpd_write_response(hc); + closedir(dirp); + exit(1); + } + + fputs(html_html, fp); + fputs(html_hdtitle, fp); + (void)fprintf(fp, "Index of %s", hc->encodedurl, hc->encodedurl); + fputs(html_titlehd, fp); + fputs(html_body, fp); + fputs(html_hdr2, fp); + (void)fprintf(fp, "Index of %s", hc->encodedurl, hc->encodedurl); + fputs(html_endhdr2, fp); + fputs(html_crlf, fp); + fputs("<PRE>\r\nmode links bytes last-changed name\r\n<HR>", fp); + + /* Read in names. */ + + nnames = 0; + while ((de = readdir(dirp)) != 0) /* dirent or direct */ + { + if (nnames >= maxnames) + { + if (maxnames == 0) + { + maxnames = 100; + names = NEW(char, maxnames * (MAXPATHLEN + 1)); + nameptrs = NEW(char*, maxnames); + } + else + { + oldmax = maxnames; + maxnames *= 2; + names = RENEW(names, char, oldmax*(MAXPATHLEN+1), maxnames*(MAXPATHLEN + 1)); + nameptrs = RENEW(nameptrs, char*, oldmax, maxnames); + } + + if (!names || !nameptrs) + { + ndbg("out of memory reallocating directory names\n"); + exit(1); + } + + for (i = 0; i < maxnames; ++i) + { + nameptrs[i] = &names[i * (MAXPATHLEN + 1)]; + } + } + + namlen = NAMLEN(de); + (void)strncpy(nameptrs[nnames], de->d_name, namlen); + nameptrs[nnames][namlen] = '\0'; + ++nnames; + } + closedir(dirp); + + /* Sort the names. */ + + qsort(nameptrs, nnames, sizeof(*nameptrs), name_compare); + + /* Generate output. */ + + for (i = 0; i < nnames; ++i) + { + httpd_realloc_str(&name, &maxname, + strlen(hc->expnfilename) + 1 + + strlen(nameptrs[i])); + httpd_realloc_str(&rname, &maxrname, + strlen(hc->origfilename) + 1 + + strlen(nameptrs[i])); + + if (hc->expnfilename[0] == '\0' || strcmp(hc->expnfilename, ".") == 0) + { + (void)strcpy(name, nameptrs[i]); + (void)strcpy(rname, nameptrs[i]); + } + else + { + (void)snprintf(name, maxname, "%s/%s", hc->expnfilename, nameptrs[i]); + if (strcmp(hc->origfilename, ".") == 0) + { + (void)snprintf(rname, maxrname, "%s", nameptrs[i]); + } + else + { + (void)snprintf(rname, maxrname, "%s%s", hc->origfilename, nameptrs[i]); + } + } + + httpd_realloc_str(&encrname, &maxencrname, 3 * strlen(rname) + 1); + httpd_strencode(encrname, maxencrname, rname); + + if (stat(name, &sb) < 0 || lstat(name, &lsb) < 0) + { + continue; + } + + linkprefix = ""; + link[0] = '\0'; + + /* Break down mode word. First the file type. */ + + switch (lsb.st_mode & S_IFMT) + { + case S_IFIFO: + modestr[0] = 'p'; + break; + + case S_IFCHR: + modestr[0] = 'c'; + break; + + case S_IFDIR: + modestr[0] = 'd'; + break; + + case S_IFBLK: + modestr[0] = 'b'; + break; + + case S_IFREG: + modestr[0] = '-'; + break; + + case S_IFSOCK: + modestr[0] = 's'; + break; + + case S_IFLNK: + default: + modestr[0] = '?'; + break; + } + + /* Now the world permissions. Owner and group permissions are + * not of interest to web clients. + */ + + modestr[1] = (lsb.st_mode & S_IROTH) ? 'r' : '-'; + modestr[2] = (lsb.st_mode & S_IWOTH) ? 'w' : '-'; + modestr[3] = (lsb.st_mode & S_IXOTH) ? 'x' : '-'; + modestr[4] = '\0'; + + /* We also leave out the owner and group name */ + + /* Get time string. */ + + now = time(NULL); + timestr = ctime(&lsb.st_mtime); + timestr[0] = timestr[4]; + timestr[1] = timestr[5]; + timestr[2] = timestr[6]; + timestr[3] = ' '; + timestr[4] = timestr[8]; + timestr[5] = timestr[9]; + timestr[6] = ' '; + + if (now - lsb.st_mtime > 60 * 60 * 24 * 182) /* 1/2 year */ + { + timestr[7] = ' '; + timestr[8] = timestr[20]; + timestr[9] = timestr[21]; + timestr[10] = timestr[22]; + timestr[11] = timestr[23]; + } + else + { + timestr[7] = timestr[11]; + timestr[8] = timestr[12]; + timestr[9] = ':'; + timestr[10] = timestr[14]; + timestr[11] = timestr[15]; + } + timestr[12] = '\0'; + + /* The ls -F file class. */ + + switch (sb.st_mode & S_IFMT) + { + case S_IFDIR: + fileclass = "/"; + break; + + case S_IFSOCK: + fileclass = "="; + break; + + case S_IFLNK: + fileclass = "@"; + break; + + default: + fileclass = (sb.st_mode & S_IXOTH) ? "*" : ""; + break; + } + + /* And print. */ + + (void)fprintf(fp, "%s %3ld %10lld %s <A HREF=\"/%.500s%s\">%s</A>%s%s%s\n", + modestr, (long)lsb.st_nlink, (int16_t) lsb.st_size, + timestr, encrname, S_ISDIR(sb.st_mode) ? "/" : "", + nameptrs[i], linkprefix, link, fileclass); + } + + fputs("</PRE>", fp); + fputs(html_endbody, fp); + fputs(html_endhtml, fp); + (void)fclose(fp); + exit(0); +} + +static int ls(httpd_conn *hc) +{ + DIR *dirp; + struct dirent *de; + int namlen; + static int maxnames = 0; + int nnames; + static char *names; + static char **nameptrs; + static char *name; + static size_t maxname = 0; + static char *rname; + static size_t maxrname = 0; + static char *encrname; + static size_t maxencrname = 0; + FILE *fp; + int i, child; + struct stat sb; + struct stat lsb; + char modestr[20]; + char *linkprefix; + char link[MAXPATHLEN + 1]; + char *fileclass; + time_t now; + char *timestr; + char arg[16]; + char *argv[1]; +#if CONFIG_THTTPD_CGI_TIMELIMIT > 0 + ClientData client_data; +#endif + + dirp = opendir(hc->expnfilename); + if (dirp == NULL) + { + ndbg("opendir %s: %d\n", hc->expnfilename, errno); + httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl); + return -1; + } + + if (hc->method == METHOD_HEAD) + { + closedir(dirp); + send_mime(hc, 200, ok200title, "", "", "text/html; charset=%s", + (off_t) - 1, hc->sb.st_mtime); + } + else if (hc->method == METHOD_GET) + { +#ifdef CONFIG_THTTPD_CGILIMIT + if (hc->hs->cgi_count >= CONFIG_THTTPD_CGILIMIT) + { + closedir(dirp); + httpd_send_err(hc, 503, httpd_err503title, "", httpd_err503form, + hc->encodedurl); + return -1; + } +#endif + ++hc->hs->cgi_count; + + /* Start the child task. */ + + snprintf(arg, 16, "%p", hc); /* task_create doesn't handle binary arguments. */ + argv[0] = arg; + +#ifndef CONFIG_CUSTOM_STACK + child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY, + CONFIG_THTTPD_CGI_STACKSIZE, + (main_t)ls_child, (const char **)argv); +#else + child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY, + (main_t)ls_child, (const char **)argv); +#endif + if (child < 0) + { + ndbg("task_create: %d\n", errno); + closedir(dirp); + INTERNALERROR("task_create"); + httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); + return -1; + } + + closedir(dirp); + ndbg("spawned indexing task %d for directory '%s'\n", child, hc->expnfilename); + + /* Schedule a kill for the child task, in case it runs too long */ + +#if CONFIG_THTTPD_CGI_TIMELIMIT > 0 + client_data.i = child; + if (tmr_create(NULL, cgi_kill, client_data, CONFIG_THTTPD_CGI_TIMELIMIT * 1000L, 0) == NULL) + { + ndbg("tmr_create(cgi_kill ls) failed\n"); + exit(1); + } +#endif + + hc->bytes_sent = CONFIG_THTTPD_CGI_BYTECOUNT; + hc->should_linger = false; + } + else + { + closedir(dirp); + NOTIMPLEMENTED(httpd_method_str(hc->method)); + httpd_send_err(hc, 501, err501title, "", err501form, httpd_method_str(hc->method)); + return -1; + } + + return 0; +} +#endif /* CONFIG_THTTPD_GENERATE_INDICES */ + +/* Returns 1 if ok to serve the url, 0 if not. */ + +static int check_referer(httpd_conn *hc) +{ + /* Are we doing referer checking at all? */ + +#ifdef CONFIG_THTTPD_URLPATTERN + int r; + char *cp; + + child = really_check_referer(hc); + + if (!r) + { +#ifdef CONFIG_THTTPD_VHOST + if (hc->vhostname != NULL) + { + cp = hc->vhostname; + } + else +#endif + { + cp = hc->hs->hostname; + } + + if (cp == NULL) + { + cp = ""; + } + + ndbg("%s non-local referer \"%s%s\" \"%s\"\n", + httpd_ntoa(&hc->client_addr), cp, hc->encodedurl, hc->referer); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "You must supply a local referer to get URL '%s' from this server.\n"), + hc->encodedurl); + } + return r; +#else + return 1; +#endif +} + +/* Returns 1 if ok to serve the url, 0 if not. */ + +#ifdef CONFIG_THTTPD_URLPATTERN +static int really_check_referer(httpd_conn *hc) +{ + httpd_server *hs; + char *cp1; + char *cp2; + char *cp3; + static char *refhost = NULL; + static size_t refhost_size = 0; + char *lp; + + hs = hc->hs; + + /* Check for an empty referer. */ + + if (hc->referer == NULL || hc->referer[0] == '\0' || + (cp1 = strstr(hc->referer, "//")) == NULL) + { + /* Disallow if the url matches. */ + + if (match(CONFIG_THTTPD_URLPATTERN, hc->origfilename)) + { + return 0; + } + + /* Otherwise ok. */ + + return 1; + } + + /* Extract referer host. */ + + cp1 += 2; + for (cp2 = cp1; *cp2 != '/' && *cp2 != ':' && *cp2 != '\0'; ++cp2) + { + continue; + } + + httpd_realloc_str(&refhost, &refhost_size, cp2 - cp1); + for (cp3 = refhost; cp1 < cp2; ++cp1, ++cp3) + if (isupper(*cp1)) + { + *cp3 = tolower(*cp1); + } + else + { + *cp3 = *cp1; + } + *cp3 = '\0'; + + /* Local pattern? */ + +#ifdef CONFIG_THTTPD_LOCALPATTERN + lp = CONFIG_THTTPD_LOCALPATTERN; +#else + + /* No local pattern. What's our hostname? */ + +#ifndef CONFIG_THTTPD_VHOST + /* Not vhosting, use the server name. */ + + lp = hs->hostname; + if (!lp) + { + /* Couldn't figure out local hostname - give up. */ + + return 1; + } + +#else + /* We are vhosting, use the hostname on this connection. */ + + lp = hc->vhostname; + if (!lp) + { + /* Oops, no hostname. Maybe it's an old browser that doesn't + * send a Host: header. We could figure out the default + * hostname for this IP address, but it's not worth it for the + * few requests like this. + */ + + return 1; + } +#endif +#endif /* CONFIG_THTTPD_LOCALPATTERN */ + + /* If the referer host doesn't match the local host pattern, and the + * filename does match the url pattern, it's an illegal reference. + */ + +#ifdef CONFIG_THTTPD_URLPATTERN + if (!match(lp, refhost) && match(CONFIG_THTTPD_URLPATTERN, hc->origfilename)) + { + return 0; + } +#endif + + /* Otherwise ok. */ + + return 1; +} +#endif + +#ifdef CONFIG_DEBUG +static int sockaddr_check(httpd_sockaddr *saP) +{ + switch (saP->sin_family) + { + case AF_INET: + return 1; + +#ifdef CONFIG_NET_IPv6 + case AF_INET6: + return 1; +#endif + + default: + return 0; + } +} +#endif + +static size_t sockaddr_len(httpd_sockaddr *saP) +{ + switch (saP->sin_family) + { + case AF_INET: + return sizeof(struct sockaddr_in); + +#ifdef CONFIG_NET_IPv6 + case AF_INET6: + return sizeof(struct sockaddr_in6); +#endif + + default: + break; + } + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +FAR httpd_server *httpd_initialize(FAR httpd_sockaddr *sa) +{ + FAR httpd_server *hs; + + /* Save the PID of the main thread */ + + main_thread = getpid(); + + /* Allocate the server structure */ + + hs = (FAR httpd_server *)zalloc(sizeof(httpd_server)); + if (!hs) + { + ndbg("out of memory allocating an httpd_server\n"); + return NULL; + } + +#ifdef CONFIG_THTTPD_HOSTNAME + hs->hostname = httpd_strdup(CONFIG_THTTPD_HOSTNAME); +#else + hs->hostname = httpd_strdup(httpd_ntoa(sa)); +#endif + nvdbg("hostname: %s\n", hs->hostname); + + if (!hs->hostname) + { + ndbg("out of memory copying hostname\n"); + return NULL; + } + + hs->cgi_count = 0; + + /* Initialize listen sockets */ + + hs->listen_fd = initialize_listen_socket(sa); + if (hs->listen_fd == -1) + { + ndbg("Failed to create listen socket\n"); + free_httpd_server(hs); + return NULL; + } + + init_mime(); + + /* Done initializing. */ + + ndbg("%s starting on port %d\n", CONFIG_THTTPD_SERVER_SOFTWARE, (int)CONFIG_THTTPD_PORT); + return hs; +} + +void httpd_terminate(httpd_server * hs) +{ + httpd_unlisten(hs); + free_httpd_server(hs); +} + +void httpd_unlisten(httpd_server * hs) +{ + if (hs->listen_fd != -1) + { + (void)close(hs->listen_fd); + hs->listen_fd = -1; + } +} + +/* Send the buffered response. */ + +void httpd_write_response(httpd_conn *hc) +{ + /* If we are in a sub-task, turn off no-delay mode. */ + + if (main_thread != getpid()) + { + httpd_clear_ndelay(hc->conn_fd); + } + + /* Send the response, if necessary. */ + + if (hc->buflen > 0) + { + (void)httpd_write(hc->conn_fd, hc->buffer, hc->buflen); + hc->buflen = 0; + } +} + +/* Set no-delay / non-blocking mode on a socket. */ + +void httpd_set_ndelay(int fd) +{ + int flags, newflags; + + flags = fcntl(fd, F_GETFL, 0); + if (flags != -1) + { + newflags = flags | (int)O_NDELAY; + if (newflags != flags) + (void)fcntl(fd, F_SETFL, newflags); + } +} + +/* Clear no-delay / non-blocking mode on a socket. */ + +void httpd_clear_ndelay(int fd) +{ + int flags, newflags; + + flags = fcntl(fd, F_GETFL, 0); + if (flags != -1) + { + newflags = flags & ~(int)O_NDELAY; + if (newflags != flags) + { + (void)fcntl(fd, F_SETFL, newflags); + } + } +} + +void httpd_send_err(httpd_conn *hc, int status, const char *title, const char *extraheads, + const char *form, const char *arg) +{ +#ifdef CONFIG_THTTPD_ERROR_DIRECTORY + char filename[1000]; + + /* Try virtual host error page. */ + + ndbg("title: \"%s\" form: \"%s\"\n", title, form); + +#ifdef CONFIG_THTTPD_VHOST + if (hc->hostdir[0] != '\0') + { + (void)snprintf(filename, sizeof(filename), + "%s/%s/err%d.html", hc->hostdir, CONFIG_THTTPD_ERROR_DIRECTORY, status); + if (send_err_file(hc, status, title, extraheads, filename)) + { + nvdbg("Sent VHOST error file\n"); + return; + } + } +#endif + + /* Try server-wide error page. */ + + (void)snprintf(filename, sizeof(filename), "%s/err%d.html", CONFIG_THTTPD_ERROR_DIRECTORY, status); + if (send_err_file(hc, status, title, extraheads, filename)) + { + nvdbg("Sent server-wide error page\n"); + return; + } + + /* Fall back on built-in error page. */ + + send_response(hc, status, title, extraheads, form, arg); + +#else + + send_response(hc, status, title, extraheads, form, arg); + +#endif +} + +const char *httpd_method_str(int method) +{ + switch (method) + { + case METHOD_GET: + return "GET"; + + case METHOD_HEAD: + return "HEAD"; + + case METHOD_POST: + return "POST"; + + default: + return "UNKNOWN"; + } +} + +int httpd_get_conn(httpd_server *hs, int listen_fd, httpd_conn *hc) +{ + httpd_sockaddr sa; + socklen_t sz; + + if (!hc->initialized) + { + hc->read_size = 0; + httpd_realloc_str(&hc->read_buf, &hc->read_size, CONFIG_THTTPD_IOBUFFERSIZE); + hc->maxdecodedurl = + hc->maxorigfilename = hc->maxexpnfilename = hc->maxencodings = + hc->maxpathinfo = hc->maxquery = hc->maxaccept = + hc->maxaccepte = hc->maxreqhost = hc->maxhostdir = + hc->maxremoteuser = 0; +#ifdef CONFIG_THTTPD_TILDE_MAP2 + hc->maxaltdir = 0; +#endif + httpd_realloc_str(&hc->decodedurl, &hc->maxdecodedurl, 1); + httpd_realloc_str(&hc->origfilename, &hc->maxorigfilename, 1); + httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, 0); + httpd_realloc_str(&hc->encodings, &hc->maxencodings, 0); + httpd_realloc_str(&hc->pathinfo, &hc->maxpathinfo, 0); + httpd_realloc_str(&hc->query, &hc->maxquery, 0); + httpd_realloc_str(&hc->accept, &hc->maxaccept, 0); + httpd_realloc_str(&hc->accepte, &hc->maxaccepte, 0); + httpd_realloc_str(&hc->reqhost, &hc->maxreqhost, 0); + httpd_realloc_str(&hc->hostdir, &hc->maxhostdir, 0); + httpd_realloc_str(&hc->remoteuser, &hc->maxremoteuser, 0); +#ifdef CONFIG_THTTPD_TILDE_MAP2 + httpd_realloc_str(&hc->altdir, &hc->maxaltdir, 0); +#endif + hc->initialized = 1; + } + + /* Accept the new connection. */ + + nvdbg("accept() new connection on listen_fd %d\n", listen_fd); + sz = sizeof(sa); + hc->conn_fd = accept(listen_fd, (struct sockaddr*)&sa, &sz); + if (hc->conn_fd < 0) + { + if (errno == EWOULDBLOCK) + { + return GC_NO_MORE; + } + + ndbg("accept failed: %d\n", errno); + return GC_FAIL; + } + +#ifdef CONFIG_DEBUG + if (!sockaddr_check(&sa)) + { + ndbg("unknown sockaddr family\n"); + close(hc->conn_fd); + hc->conn_fd = -1; + return GC_FAIL; + } +#endif + + hc->hs = hs; + (void)memset(&hc->client_addr, 0, sizeof(hc->client_addr)); + (void)memmove(&hc->client_addr, &sa, sockaddr_len(&sa)); + hc->read_idx = 0; + hc->checked_idx = 0; + hc->checked_state = CHST_FIRSTWORD; + hc->method = METHOD_UNKNOWN; + hc->bytes_to_send = 0; + hc->bytes_sent = 0; + hc->encodedurl = ""; + hc->decodedurl[0] = '\0'; + hc->protocol = "UNKNOWN"; + hc->origfilename[0] = '\0'; + hc->expnfilename[0] = '\0'; + hc->encodings[0] = '\0'; + hc->pathinfo[0] = '\0'; + hc->query[0] = '\0'; + hc->referer = ""; + hc->useragent = ""; + hc->accept[0] = '\0'; + hc->accepte[0] = '\0'; + hc->acceptl = ""; + hc->cookie = ""; + hc->contenttype = ""; + hc->reqhost[0] = '\0'; + hc->hdrhost = ""; + hc->hostdir[0] = '\0'; + hc->authorization = ""; + hc->remoteuser[0] = '\0'; + hc->buffer[0] = '\0'; +#ifdef CONFIG_THTTPD_TILDE_MAP2 + hc->altdir[0] = '\0'; +#endif + hc->buflen = 0; + hc->if_modified_since = (time_t) - 1; + hc->range_if = (time_t)-1; + hc->contentlength = -1; + hc->type = ""; +#ifdef CONFIG_THTTPD_VHOST + hc->vhostname = NULL; +#endif + hc->mime_flag = true; + hc->one_one = false; + hc->got_range = false; + hc->tildemapped = false; + hc->range_start = 0; + hc->range_end = -1; + hc->keep_alive = false; + hc->should_linger = false; + hc->file_fd = -1; + + nvdbg("New connection accepted on %d\n", hc->conn_fd); + return GC_OK; +} + +/* Checks hc->read_buf to see whether a complete request has been read so far; + * either the first line has two words (an HTTP/0.9 request), or the first + * line has three words and there's a blank line present. + * + * hc->read_idx is how much has been read in; hc->checked_idx is how much we + * have checked so far; and hc->checked_state is the current state of the + * finite state machine. + */ + +int httpd_got_request(httpd_conn *hc) +{ + char c; + + for (; hc->checked_idx < hc->read_idx; ++hc->checked_idx) + { + c = hc->read_buf[hc->checked_idx]; + switch (hc->checked_state) + { + case CHST_FIRSTWORD: + switch (c) + { + case ' ': + case '\t': + hc->checked_state = CHST_FIRSTWS; + break; + + case '\012': + case '\015': + hc->checked_state = CHST_BOGUS; + return GR_BAD_REQUEST; + } + break; + + case CHST_FIRSTWS: + switch (c) + { + case ' ': + case '\t': + break; + + case '\012': + case '\015': + hc->checked_state = CHST_BOGUS; + return GR_BAD_REQUEST; + + default: + hc->checked_state = CHST_SECONDWORD; + break; + } + break; + + case CHST_SECONDWORD: + switch (c) + { + case ' ': + case '\t': + hc->checked_state = CHST_SECONDWS; + break; + + case '\012': + case '\015': + /* The first line has only two words - an HTTP/0.9 request. */ + return GR_GOT_REQUEST; + } + break; + + case CHST_SECONDWS: + switch (c) + { + case ' ': + case '\t': + break; + + case '\012': + case '\015': + hc->checked_state = CHST_BOGUS; + return GR_BAD_REQUEST; + + default: + hc->checked_state = CHST_THIRDWORD; + break; + } + break; + + case CHST_THIRDWORD: + switch (c) + { + case ' ': + case '\t': + hc->checked_state = CHST_THIRDWS; + break; + + case '\012': + hc->checked_state = CHST_LF; + break; + + case '\015': + hc->checked_state = CHST_CR; + break; + } + break; + + case CHST_THIRDWS: + switch (c) + { + case ' ': + case '\t': + break; + + case '\012': + hc->checked_state = CHST_LF; + break; + + case '\015': + hc->checked_state = CHST_CR; + break; + + default: + hc->checked_state = CHST_BOGUS; + return GR_BAD_REQUEST; + } + break; + + case CHST_LINE: + switch (c) + { + case '\012': + hc->checked_state = CHST_LF; + break; + + case '\015': + hc->checked_state = CHST_CR; + break; + } + break; + + case CHST_LF: + switch (c) + { + case '\012': + /* Two newlines in a row - a blank line - end of request. */ + + return GR_GOT_REQUEST; + + case '\015': + hc->checked_state = CHST_CR; + break; + + default: + hc->checked_state = CHST_LINE; + break; + } + break; + + case CHST_CR: + switch (c) + { + case '\012': + hc->checked_state = CHST_CRLF; + break; + + case '\015': + /* Two returns in a row - end of request. */ + + return GR_GOT_REQUEST; + + default: + hc->checked_state = CHST_LINE; + break; + } + break; + + case CHST_CRLF: + switch (c) + { + case '\012': + /* Two newlines in a row - end of request. */ + + return GR_GOT_REQUEST; + + case '\015': + hc->checked_state = CHST_CRLFCR; + break; + + default: + hc->checked_state = CHST_LINE; + break; + } + break; + + case CHST_CRLFCR: + switch (c) + { + case '\012': + case '\015': + /* Two CRLFs or two CRs in a row - end of request. */ + + return GR_GOT_REQUEST; + + default: + hc->checked_state = CHST_LINE; + break; + } + break; + + case CHST_BOGUS: + return GR_BAD_REQUEST; + } + } + return GR_NO_REQUEST; +} + +int httpd_parse_request(httpd_conn *hc) +{ + char *buf; + char *method_str; + char *url; + char *protocol; + char *reqhost; + char *eol; + char *cp; + char *pi; + + hc->checked_idx = 0; /* reset */ + method_str = bufgets(hc); + nvdbg("method_str: \"%s\"\n", method_str); + + url = strpbrk(method_str, " \t\012\015"); + if (!url) + { + BADREQUEST("url-1"); + httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); + return -1; + } + + *url++ = '\0'; + url += strspn(url, " \t\012\015"); + nvdbg("url: \"%s\"\n", url); + + protocol = strpbrk(url, " \t\012\015"); + nvdbg("protocol: \"%s\"\n", protocol ? protocol : "<null>"); + + if (!protocol) + { + protocol = "HTTP/0.9"; + hc->mime_flag = false; + } + else + { + *protocol++ = '\0'; + protocol += strspn(protocol, " \t\012\015"); + if (*protocol != '\0') + { + eol = strpbrk(protocol, " \t\012\015"); + if (eol) + { + *eol = '\0'; + } + + if (strcasecmp(protocol, "HTTP/1.0") != 0) + { + hc->one_one = true; + } + } + } + hc->protocol = protocol; + + /* Check for HTTP/1.1 absolute URL. */ + + if (strncasecmp(url, "http://", 7) == 0) + { + if (!hc->one_one) + { + BADREQUEST("one_one"); + httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); + return -1; + } + + reqhost = url + 7; + url = strchr(reqhost, '/'); + if (!url) + { + BADREQUEST("reqhost-1"); + httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); + return -1; + } + *url = '\0'; + + if (strchr(reqhost, '/') != NULL || reqhost[0] == '.') + { + BADREQUEST("reqhost-2"); + httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); + return -1; + } + + httpd_realloc_str(&hc->reqhost, &hc->maxreqhost, strlen(reqhost)); + (void)strcpy(hc->reqhost, reqhost); + *url = '/'; + } + + if (*url != '/') + { + BADREQUEST("url-2"); + httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); + return -1; + } + + if (strcasecmp(method_str, httpd_method_str(METHOD_GET)) == 0) + { + hc->method = METHOD_GET; + } + else if (strcasecmp(method_str, httpd_method_str(METHOD_HEAD)) == 0) + { + hc->method = METHOD_HEAD; + } + else if (strcasecmp(method_str, httpd_method_str(METHOD_POST)) == 0) + { + hc->method = METHOD_POST; + } + else + { + NOTIMPLEMENTED(method_str); + httpd_send_err(hc, 501, err501title, "", err501form, method_str); + return -1; + } + + hc->encodedurl = url; + httpd_realloc_str(&hc->decodedurl, &hc->maxdecodedurl, strlen(hc->encodedurl)); + httpd_strdecode(hc->decodedurl, hc->encodedurl); + + httpd_realloc_str(&hc->origfilename, &hc->maxorigfilename, strlen(hc->decodedurl)); + (void)strcpy(hc->origfilename, &hc->decodedurl[1]); + + /* Special case for top-level URL. */ + + if (hc->origfilename[0] == '\0') + { + (void)strcpy(hc->origfilename, "."); + } + + /* Extract query string from encoded URL. */ + + cp = strchr(hc->encodedurl, '?'); + if (cp) + { + ++cp; + httpd_realloc_str(&hc->query, &hc->maxquery, strlen(cp)); + (void)strcpy(hc->query, cp); + + /* Remove query from (decoded) origfilename. */ + + cp = strchr(hc->origfilename, '?'); + if (cp) + { + *cp = '\0'; + } + } + + de_dotdot(hc->origfilename); + if (hc->origfilename[0] == '/' || + (hc->origfilename[0] == '.' && hc->origfilename[1] == '.' && + (hc->origfilename[2] == '\0' || hc->origfilename[2] == '/'))) + { + BADREQUEST("origfilename"); + httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); + return -1; + } + + if (hc->mime_flag) + { + /* Read the MIME headers. */ + while ((buf = bufgets(hc)) != NULL) + { + if (buf[0] == '\0') + { + break; + } + + if (strncasecmp(buf, "Referer:", 8) == 0) + { + cp = &buf[8]; + cp += strspn(cp, " \t"); + hc->referer = cp; + } + else if (strncasecmp(buf, "User-Agent:", 11) == 0) + { + cp = &buf[11]; + cp += strspn(cp, " \t"); + hc->useragent = cp; + } + else if (strncasecmp(buf, "Host:", 5) == 0) + { + cp = &buf[5]; + cp += strspn(cp, " \t"); + hc->hdrhost = cp; + cp = strchr(hc->hdrhost, ':'); + if (cp) + { + *cp = '\0'; + } + + if (strchr(hc->hdrhost, '/') != NULL || hc->hdrhost[0] == '.') + { + BADREQUEST("hdrhost"); + httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); + return -1; + } + } + else if (strncasecmp(buf, "Accept:", 7) == 0) + { + cp = &buf[7]; + cp += strspn(cp, " \t"); + if (hc->accept[0] != '\0') + { + if (strlen(hc->accept) > CONFIG_THTTPD_MAXREALLOC) + { + ndbg("%s way too much Accept: data\n", + httpd_ntoa(&hc->client_addr)); + continue; + } + httpd_realloc_str(&hc->accept, &hc->maxaccept, strlen(hc->accept) + 2 + strlen(cp)); + (void)strcat(hc->accept, ", "); + } + else + { + httpd_realloc_str(&hc->accept, &hc->maxaccept, strlen(cp)); + } + (void)strcat(hc->accept, cp); + } + else if (strncasecmp(buf, "Accept-Encoding:", 16) == 0) + { + cp = &buf[16]; + cp += strspn(cp, " \t"); + if (hc->accepte[0] != '\0') + { + if (strlen(hc->accepte) > CONFIG_THTTPD_MAXREALLOC) + { + ndbg("%s way too much Accept-Encoding: data\n", + httpd_ntoa(&hc->client_addr)); + continue; + } + httpd_realloc_str(&hc->accepte, &hc->maxaccepte, strlen(hc->accepte) + 2 + strlen(cp)); + (void)strcat(hc->accepte, ", "); + } + else + { + httpd_realloc_str(&hc->accepte, &hc->maxaccepte, strlen(cp)); + } + (void)strcpy(hc->accepte, cp); + } + else if (strncasecmp(buf, "Accept-Language:", 16) == 0) + { + cp = &buf[16]; + cp += strspn(cp, " \t"); + hc->acceptl = cp; + } + else if (strncasecmp(buf, "If-Modified-Since:", 18) == 0) + { + cp = &buf[18]; + hc->if_modified_since = tdate_parse(cp); + if (hc->if_modified_since == (time_t) - 1) + ndbg("unparsable time: %s\n", cp); + } + else if (strncasecmp(buf, "Cookie:", 7) == 0) + { + cp = &buf[7]; + cp += strspn(cp, " \t"); + hc->cookie = cp; + } + else if (strncasecmp(buf, "Range:", 6) == 0) + { + /* Only support %d- and %d-%d, not %d-%d,%d-%d or -%d. */ + if (strchr(buf, ',') == NULL) + { + char *cp_dash; + cp = strpbrk(buf, "="); + if (cp) + { + cp_dash = strchr(cp + 1, '-'); + if (cp_dash != NULL && cp_dash != cp + 1) + { + *cp_dash = '\0'; + hc->got_range = true; + hc->range_start = atoll(cp + 1); + if (hc->range_start < 0) + { + hc->range_start = 0; + } + + if (isdigit((int)cp_dash[1])) + { + hc->range_end = atoll(cp_dash + 1); + if (hc->range_end < 0) + hc->range_end = -1; + } + } + } + } + } + else if (strncasecmp(buf, "Range-If:", 9) == 0 || + strncasecmp(buf, "If-Range:", 9) == 0) + { + cp = &buf[9]; + hc->range_if = tdate_parse(cp); + if (hc->range_if == (time_t) - 1) + { + ndbg("unparsable time: %s\n", cp); + } + } + else if (strncasecmp(buf, "Content-Type:", 13) == 0) + { + cp = &buf[13]; + cp += strspn(cp, " \t"); + hc->contenttype = cp; + } + else if (strncasecmp(buf, "Content-Length:", 15) == 0) + { + cp = &buf[15]; + hc->contentlength = atol(cp); + } + else if (strncasecmp(buf, "Authorization:", 14) == 0) + { + cp = &buf[14]; + cp += strspn(cp, " \t"); + hc->authorization = cp; + } + else if (strncasecmp(buf, "Connection:", 11) == 0) + { + cp = &buf[11]; + cp += strspn(cp, " \t"); + if (strcasecmp(cp, "keep-alive") == 0) + { + hc->keep_alive = true; + } + } +#ifdef LOG_UNKNOWN_HEADERS + else if (strncasecmp(buf, "Accept-Charset:", 15) == 0 || + strncasecmp(buf, "Accept-Language:", 16) == 0 || + strncasecmp(buf, "Agent:", 6) == 0 || + strncasecmp(buf, "Cache-Control:", 14) == 0 || + strncasecmp(buf, "Cache-Info:", 11) == 0 || + strncasecmp(buf, "Charge-To:", 10) == 0 || + strncasecmp(buf, "Client-IP:", 10) == 0 || + strncasecmp(buf, "Date:", 5) == 0 || + strncasecmp(buf, "Extension:", 10) == 0 || + strncasecmp(buf, "Forwarded:", 10) == 0 || + strncasecmp(buf, "From:", 5) == 0 || + strncasecmp(buf, "HTTP-Version:", 13) == 0 || + strncasecmp(buf, "Max-Forwards:", 13) == 0 || + strncasecmp(buf, "Message-Id:", 11) == 0 || + strncasecmp(buf, "MIME-Version:", 13) == 0 || + strncasecmp(buf, "Negotiate:", 10) == 0 || + strncasecmp(buf, "Pragma:", 7) == 0 || + strncasecmp(buf, "Proxy-Agent:", 12) == 0 || + strncasecmp(buf, "Proxy-Connection:", 17) == 0 || + strncasecmp(buf, "Security-Scheme:", 16) == 0 || + strncasecmp(buf, "Session-Id:", 11) == 0 || + strncasecmp(buf, "UA-Color:", 9) == 0 || + strncasecmp(buf, "UA-CPU:", 7) == 0 || + strncasecmp(buf, "UA-Disp:", 8) == 0 || + strncasecmp(buf, "UA-OS:", 6) == 0 || + strncasecmp(buf, "UA-Pixels:", 10) == 0 || + strncasecmp(buf, "User:", 5) == 0 || + strncasecmp(buf, "Via:", 4) == 0 || + strncasecmp(buf, "X-", 2) == 0) + ; /* ignore */ + else + { + ndbg("unknown request header: %s\n", buf); + } +#endif + } + } + + if (hc->one_one) + { + /* Check that HTTP/1.1 requests specify a host, as required. */ + + if (hc->reqhost[0] == '\0' && hc->hdrhost[0] == '\0') + { + BADREQUEST("reqhost-3"); + httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); + return -1; + } + + /* If the client wants to do keep-alives, it might also be doing + * pipelining. There's no way for us to tell. Since we don't + * implement keep-alives yet, if we close such a connection there + * might be unread pipelined requests waiting. So, we have to do a + * lingering close. + */ + + if (hc->keep_alive) + { + hc->should_linger = true; + } + } + + /* Ok, the request has been parsed. Now we resolve stuff that may require + * the entire request. + */ + + /* Copy original filename to expanded filename. */ + + httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, + strlen(hc->origfilename)); + (void)strcpy(hc->expnfilename, hc->origfilename); + + /* Tilde mapping. */ + + if (hc->expnfilename[0] == '~') + { +#ifdef CONFIG_THTTPD_TILDE_MAP1 + if (!httpd_tilde_map1(hc)) + { + httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl); + return -1; + } +#endif +#ifdef CONFIG_THTTPD_TILDE_MAP2 + if (!httpd_tilde_map2(hc)) + { + httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl); + return -1; + } +#endif + } + + /* Virtual host mapping. */ + +#ifdef CONFIG_THTTPD_VHOST + if (!vhost_map(hc)) + { + INTERNALERROR("VHOST"); + httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); + return -1; + } +#endif + + /* Expand the filename */ + + cp = expand_filename(hc->expnfilename, &pi, hc->tildemapped); + if (!cp) + { + INTERNALERROR(hc->expnfilename); + httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); + return -1; + } + + httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, strlen(cp)); + (void)strcpy(hc->expnfilename, cp); + httpd_realloc_str(&hc->pathinfo, &hc->maxpathinfo, strlen(pi)); + (void)strcpy(hc->pathinfo, pi); + nvdbg("expnfilename: \"%s\" pathinfo: \"%s\"\n", hc->expnfilename, hc->pathinfo); + + /* Remove pathinfo stuff from the original filename too. */ + + if (hc->pathinfo[0] != '\0') + { + int i; + i = strlen(hc->origfilename) - strlen(hc->pathinfo); + if (i > 0 && strcmp(&hc->origfilename[i], hc->pathinfo) == 0) + { + hc->origfilename[i - 1] = '\0'; + } + } + + /* If the expanded filename is an absolute path, check that it's still + * within the current directory or the alternate directory. + */ + + if (hc->expnfilename[0] == '/') + { + if (strncmp(hc->expnfilename, httpd_root, strlen(httpd_root)) == 0) + { + } +#ifdef CONFIG_THTTPD_TILDE_MAP2 + else if (hc->altdir[0] != '\0' && + (strncmp(hc->expnfilename, hc->altdir, strlen(hc->altdir)) == 0 && + (hc->expnfilename[strlen(hc->altdir)] == '\0' || + hc->expnfilename[strlen(hc->altdir)] == '/'))) + { + } +#endif + else + { + ndbg("%s URL \"%s\" goes outside the web tree\n", + httpd_ntoa(&hc->client_addr), hc->encodedurl); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' resolves to a file outside the permitted web server directory tree.\n"), + hc->encodedurl); + return -1; + } + } + + return 0; +} + +void httpd_close_conn(httpd_conn *hc) +{ + if (hc->file_fd >= 0) + { + (void)close(hc->file_fd); + hc->file_fd = -1; + } + + if (hc->conn_fd >= 0) + { + (void)close(hc->conn_fd); + hc->conn_fd = -1; + } +} + +void httpd_destroy_conn(httpd_conn *hc) +{ + if (hc->initialized) + { + httpd_free((void *)hc->read_buf); + httpd_free((void *)hc->decodedurl); + httpd_free((void *)hc->origfilename); + httpd_free((void *)hc->expnfilename); + httpd_free((void *)hc->encodings); + httpd_free((void *)hc->pathinfo); + httpd_free((void *)hc->query); + httpd_free((void *)hc->accept); + httpd_free((void *)hc->accepte); + httpd_free((void *)hc->reqhost); + httpd_free((void *)hc->hostdir); + httpd_free((void *)hc->remoteuser); + httpd_free((void *)hc->buffer); +#ifdef CONFIG_THTTPD_TILDE_MAP2 + httpd_free((void *)hc->altdir); +#endif /*CONFIG_THTTPD_TILDE_MAP2 */ + hc->initialized = 0; + } +} + +int httpd_start_request(httpd_conn *hc, struct timeval *nowP) +{ + static char *indexname; + static size_t maxindexname = 0; +#ifdef CONFIG_THTTPD_AUTH_FILE + static char *dirname; + static size_t maxdirname = 0; +#endif /* CONFIG_THTTPD_AUTH_FILE */ + size_t expnlen, indxlen; + char *cp; + char *pi; + int i; + + nvdbg("File: \"%s\"\n", hc->expnfilename); + expnlen = strlen(hc->expnfilename); + + if (hc->method != METHOD_GET && hc->method != METHOD_HEAD && + hc->method != METHOD_POST) + { + NOTIMPLEMENTED("start"); + httpd_send_err(hc, 501, err501title, "", err501form, + httpd_method_str(hc->method)); + return -1; + } + + /* Stat the file. */ + + if (stat(hc->expnfilename, &hc->sb) < 0) + { + INTERNALERROR(hc->expnfilename); + httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); + return -1; + } + + /* Is it world-readable or world-executable? We check explicitly instead + * of just trying to open it, so that no one ever gets surprised by a file + * that's not set world-readable and yet somehow is readable by the HTTP + * server and therefore the *whole* world. + */ + + if (!(hc->sb.st_mode & (S_IROTH | S_IXOTH))) + { + ndbg("%s URL \"%s\" resolves to a non world-readable file\n", + httpd_ntoa(&hc->client_addr), hc->encodedurl); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' resolves to a file that is not world-readable.\n"), + hc->encodedurl); + return -1; + } + + /* Is it a directory? */ + + if (S_ISDIR(hc->sb.st_mode)) + { + /* If there's pathinfo, it's just a non-existent file. */ + + if (hc->pathinfo[0] != '\0') + { + httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl); + return -1; + } + + /* Special handling for directory URLs that don't end in a slash. We + * send back an explicit redirect with the slash, because otherwise + * many clients can't build relative URLs properly. + */ + + if (strcmp(hc->origfilename, "") != 0 && + strcmp(hc->origfilename, ".") != 0 && + hc->origfilename[strlen(hc->origfilename) - 1] != '/') + { + send_dirredirect(hc); + return -1; + } + + /* Check for an index file. */ + + for (i = 0; i < sizeof(index_names) / sizeof(char *); ++i) + { + httpd_realloc_str(&indexname, &maxindexname, + expnlen + 1 + strlen(index_names[i])); + (void)strcpy(indexname, hc->expnfilename); + indxlen = strlen(indexname); + if (indxlen == 0 || indexname[indxlen - 1] != '/') + { + (void)strcat(indexname, "/"); + } + + if (strcmp(indexname, "./") == 0) + { + indexname[0] = '\0'; + } + + (void)strcat(indexname, index_names[i]); + if (stat(indexname, &hc->sb) >= 0) + { + goto got_one; + } + } + + /* Nope, no index file, so it's an actual directory request. */ +#ifdef CONFIG_THTTPD_GENERATE_INDICES + /* Directories must be readable for indexing. */ + if (!(hc->sb.st_mode & S_IROTH)) + { + ndbg("%s URL \"%s\" tried to index a directory with indexing disabled\n", + httpd_ntoa(&hc->client_addr), hc->encodedurl); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' resolves to a directory that has indexing disabled.\n"), + hc->encodedurl); + return -1; + } +# ifdef CONFIG_THTTPD_AUTH_FILE + /* Check authorization for this directory. */ + + if (auth_check(hc, hc->expnfilename) == -1) + { + return -1; + } +# endif /* CONFIG_THTTPD_AUTH_FILE */ + + /* Referer check. */ + + if (!check_referer(hc)) + { + return -1; + } + + /* Ok, generate an index. */ + return ls(hc); +#else + ndbg("%s URL \"%s\" tried to index a directory\n", + httpd_ntoa(&hc->client_addr), hc->encodedurl); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' is a directory, and directory indexing is disabled on this server.\n"), + hc->encodedurl); + return -1; +#endif + + got_one: + + /* Got an index file. Expand again. More pathinfo means + * something went wrong. + */ + + cp = expand_filename(indexname, &pi, hc->tildemapped); + if (cp == NULL || pi[0] != '\0') + { + INTERNALERROR(indexname); + httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); + return -1; + } + + expnlen = strlen(cp); + httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, expnlen); + (void)strcpy(hc->expnfilename, cp); + + /* Now, is the index version world-readable or world-executable? */ + + if (!(hc->sb.st_mode & (S_IROTH | S_IXOTH))) + { + ndbg("%s URL \"%s\" resolves to a non-world-readable index file\n", + httpd_ntoa(&hc->client_addr), hc->encodedurl); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' resolves to an index file that is not world-readable.\n"), + hc->encodedurl); + return -1; + } + } + + /* Check authorization for this directory. */ + +#ifdef CONFIG_THTTPD_AUTH_FILE + httpd_realloc_str(&dirname, &maxdirname, expnlen); + (void)strcpy(dirname, hc->expnfilename); + cp = strrchr(dirname, '/'); + if (!cp) + { + (void)strcpy(dirname, httpd_root); + } + else + { + *cp = '\0'; + } + + if (auth_check(hc, dirname) == -1) + { + return -1; + } + + /* Check if the filename is the CONFIG_THTTPD_AUTH_FILE itself - that's verboten. */ + + if (expnlen == sizeof(CONFIG_THTTPD_AUTH_FILE) - 1) + { + if (strcmp(hc->expnfilename, CONFIG_THTTPD_AUTH_FILE) == 0) + { + ndbg("%s URL \"%s\" tried to retrieve an auth file\n", + httpd_ntoa(&hc->client_addr), hc->encodedurl); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' is an authorization file, retrieving it is not permitted.\n"), + hc->encodedurl); + return -1; + } + } + else if (expnlen >= sizeof(CONFIG_THTTPD_AUTH_FILE) && + strcmp(&(hc->expnfilename[expnlen - sizeof(CONFIG_THTTPD_AUTH_FILE) + 1]), + CONFIG_THTTPD_AUTH_FILE) == 0 && + hc->expnfilename[expnlen - sizeof(CONFIG_THTTPD_AUTH_FILE)] == '/') + { + ndbg("%s URL \"%s\" tried to retrieve an auth file\n", + httpd_ntoa(&hc->client_addr), hc->encodedurl); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' is an authorization file, retrieving it is not permitted.\n"), + hc->encodedurl); + return -1; + } +#endif + + /* Referer check. */ + + if (!check_referer(hc)) + return -1; + + /* Is it in the CGI area? */ + +#ifdef CONFIG_THTTPD_CGI_PATTERN + if (match(CONFIG_THTTPD_CGI_PATTERN, hc->expnfilename)) + { + return cgi(hc); + } +#endif + + /* It's not CGI. If it's executable or there's pathinfo, someone's trying + * to either serve or run a non-CGI file as CGI. Either case is + * prohibited. + */ + + if (hc->sb.st_mode & S_IXOTH) + { + ndbg("%s URL \"%s\" is executable but isn't CGI\n", + httpd_ntoa(&hc->client_addr), hc->encodedurl); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' resolves to a file which is marked executable but is not a CGI file; retrieving it is forbidden.\n"), + hc->encodedurl); + return -1; + } + + if (hc->pathinfo[0] != '\0') + { + ndbg("%s URL \"%s\" has pathinfo but isn't CGI\n", + httpd_ntoa(&hc->client_addr), hc->encodedurl); + httpd_send_err(hc, 403, err403title, "", + ERROR_FORM(err403form, + "The requested URL '%s' resolves to a file plus CGI-style pathinfo, but the file is not a valid CGI file.\n"), + hc->encodedurl); + return -1; + } + + /* Fill in range_end, if necessary. */ + + if (hc->got_range && + (hc->range_end == -1 || hc->range_end >= hc->sb.st_size)) + { + hc->range_end = hc->sb.st_size - 1; + } + + figure_mime(hc); + + if (hc->method == METHOD_HEAD) + { + send_mime(hc, 200, ok200title, hc->encodings, "", hc->type, + hc->sb.st_size, hc->sb.st_mtime); + } + else if (hc->if_modified_since != (time_t) - 1 && + hc->if_modified_since >= hc->sb.st_mtime) + { + send_mime(hc, 304, err304title, hc->encodings, "", hc->type, (off_t) - 1, + hc->sb.st_mtime); + } + else + { + hc->file_fd = open(hc->expnfilename, O_RDONLY); + if (!hc->file_fd < 0) + { + INTERNALERROR(hc->expnfilename); + httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); + return -1; + } + send_mime(hc, 200, ok200title, hc->encodings, "", hc->type, + hc->sb.st_size, hc->sb.st_mtime); + } + + return 0; +} + +char *httpd_ntoa(httpd_sockaddr *saP) +{ +#ifdef CONFIG_NET_IPv6 + static char str[200]; + + if (getnameinfo + (&saP->sa, sockaddr_len(saP), str, sizeof(str), 0, 0, + NI_NUMERICHOST) != 0) + { + str[0] = '?'; + str[1] = '\0'; + } + else if (IN6_IS_ADDR_V4MAPPED(&saP->sa_in6.sin6_addr) && + strncmp(str, "::ffff:", 7) == 0) + { + /* Elide IPv6ish prefix for IPv4 addresses. */ + + (void)strcpy(str, &str[7]); + } + + return str; + +#else /* CONFIG_NET_IPv6 */ + + return inet_ntoa(saP->sin_addr); + +#endif +} + +/* Read to requested buffer, accounting for interruptions and EOF */ + +int httpd_read(int fd, const void *buf, size_t nbytes) +{ + ssize_t nread; + int ntotal; + + ntotal = 0; + do + { + nread = read(fd, (char*)buf + ntotal, nbytes - ntotal); + if (nread < 0) + { + if (errno == EAGAIN) + { + usleep(100000); /* 100MS */ + } + else if (errno != EINTR) + { + ndbg("Error sending: %d\n", errno); + return nread; + } + } + else + { + ntotal += nread; + } + } + while (ntotal < nbytes && nread != 0); + return ntotal; +} + +/* Write the requested buffer completely, accounting for interruptions */ + +int httpd_write(int fd, const void *buf, size_t nbytes) +{ + ssize_t nwritten; + int ntotal; + + ntotal = 0; + do + { + nwritten = write(fd, (char*)buf + ntotal, nbytes - ntotal); + if (nwritten < 0) + { + if (errno == EAGAIN) + { + usleep(100000); /* 100MS */ + } + else if (errno != EINTR) + { + ndbg("Error sending: %d\n", errno); + return nwritten; + } + } + else + { + ntotal += nwritten; + } + } + while (ntotal < nbytes); + return ntotal; +} + +#endif /* CONFIG_THTTPD */ + diff --git a/apps/netutils/thttpd/libhttpd.h b/apps/netutils/thttpd/libhttpd.h new file mode 100644 index 000000000..f2e39e04d --- /dev/null +++ b/apps/netutils/thttpd/libhttpd.h @@ -0,0 +1,342 @@ +/**************************************************************************** + * netutils/thttpd/libhttpd.h + * HTTP Protocol Library Definitions + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NETUTILS_THTTPD_LIBHTTPD_H +#define __NETUTILS_THTTPD_LIBHTTPD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdint.h> +#include <stdbool.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <time.h> + +#include "config.h" +#ifdef CONFIG_THTTPD + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* A few convenient defines. */ + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* Enable special instrumentation to track down "400 Bad Request" problems */ + +#undef CONFIG_THTTPD_BADREQUEST /* Define to enable "Bad Request" instrumentation */ + +#ifdef CONFIG_THTTPD_BADREQUEST +# if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_NET) +# undef CONFIG_THTTPD_BADREQUEST +# else +# define BADREQUEST(s) nvdbg("Bad Request: \"%s\"\n", s) +# endif +#endif + +#ifndef CONFIG_THTTPD_BADREQUEST +# undef BADREQUEST +# define BADREQUEST(s) +#endif + +/* Enable special instrumentation to track down "501 Not Implemented" problems */ + +#undef CONFIG_THTTPD_NOTIMPLEMENTED /* Define to enable "Not Implemented" instrumentation */ + +#ifdef CONFIG_THTTPD_NOTIMPLEMENTED +# if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_NET) +# undef CONFIG_THTTPD_NOTIMPLEMENTED +# else +# define NOTIMPLEMENTED(s) nvdbg("Not Implemented: \"%s\"\n", s) +# endif +#endif + +#ifndef CONFIG_THTTPD_NOTIMPLEMENTED +# undef NOTIMPLEMENTED +# define NOTIMPLEMENTED(s) +#endif + +/* Enable special instrumentation to track down "500 Internal Error" problems */ + +#undef CONFIG_THTTPD_INTERNALERROR /* Define to enable "Internal Error" instrumentation */ + +#ifdef CONFIG_THTTPD_INTERNALERROR +# if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_NET) +# undef CONFIG_THTTPD_INTERNALERROR +# else +# define INTERNALERROR(s) nvdbg("Internal Error: \"%s\"\n", s) +# endif +#endif + +#ifndef CONFIG_THTTPD_INTERNALERROR +# undef INTERNALERROR +# define INTERNALERROR(s) +#endif + +/* Methods */ + +#define METHOD_UNKNOWN 0 +#define METHOD_GET 1 +#define METHOD_HEAD 2 +#define METHOD_POST 3 + +/* States for checked_state. */ + +#define CHST_FIRSTWORD 0 +#define CHST_FIRSTWS 1 +#define CHST_SECONDWORD 2 +#define CHST_SECONDWS 3 +#define CHST_THIRDWORD 4 +#define CHST_THIRDWS 5 +#define CHST_LINE 6 +#define CHST_LF 7 +#define CHST_CR 8 +#define CHST_CRLF 9 +#define CHST_CRLFCR 10 +#define CHST_BOGUS 11 + +#define GC_FAIL 0 +#define GC_OK 1 +#define GC_NO_MORE 2 + +#define GR_NO_REQUEST 0 +#define GR_GOT_REQUEST 1 +#define GR_BAD_REQUEST 2 + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/* A multi-family sockaddr. */ + +#ifdef CONFIG_NET_IPv6 +typedef struct sockaddr_in6 httpd_sockaddr; +#else +typedef struct sockaddr_in httpd_sockaddr; +#endif + +/* A server. */ + +typedef struct +{ + char *hostname; + int cgi_count; + int listen_fd; +} httpd_server; + +/* A connection. */ + +typedef struct +{ + int initialized; + httpd_server *hs; + httpd_sockaddr client_addr; + char *read_buf; + size_t read_size, read_idx, checked_idx; + int checked_state; + int method; + off_t bytes_to_send; + off_t bytes_sent; + char *encodedurl; + char *decodedurl; + char *protocol; + char *origfilename; + char *expnfilename; + char *encodings; + char *pathinfo; + char *query; + char *referer; + char *useragent; + char *accept; + char *accepte; + char *acceptl; + char *cookie; + char *contenttype; + char *reqhost; + char *hdrhost; + char *hostdir; + char *authorization; + char *remoteuser; + size_t maxdecodedurl, maxorigfilename, maxexpnfilename, maxencodings, + maxpathinfo, maxquery, maxaccept, maxaccepte, maxreqhost, maxhostdir, + maxremoteuser, maxresponse; +#ifdef CONFIG_THTTPD_TILDE_MAP2 + char *altdir; + size_t maxaltdir; +#endif + time_t if_modified_since, range_if; + size_t contentlength; + char *type; /* not malloc()ed */ +#ifdef CONFIG_THTTPD_VHOST + char *vhostname; /* not malloc()ed */ +#endif + bool mime_flag; + bool one_one; /* HTTP/1.1 or better */ + bool got_range; + bool tildemapped; /* this connection got tilde-mapped */ + bool keep_alive; + bool should_linger; + int conn_fd; /* Connection to the client */ + int file_fd; /* Descriptor for open, outgoing file */ + off_t range_start; /* File range start from Range= */ + off_t range_end; /* File range end from Range= */ + struct stat sb; + + /* This is the I/O buffer that is used to buffer portions of outgoing files */ + + uint16_t buflen; /* Index to first valid data in buffer */ + uint8_t buffer[CONFIG_THTTPD_IOBUFFERSIZE]; +} httpd_conn; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Initializes. Does the socket(), bind(), and listen(). Returns an + * httpd_server* which includes a socket fd that you can select() on. + * Return (httpd_server*) 0 on error. + */ + +extern FAR httpd_server *httpd_initialize(FAR httpd_sockaddr *sa); + +/* Call to unlisten/close socket(s) listening for new connections. */ + +extern void httpd_unlisten(httpd_server *hs); + +/* Call to shut down. */ + +extern void httpd_terminate(httpd_server *hs); + +/* When a listen fd is ready to read, call this. It does the accept() and + * returns an httpd_conn* which includes the fd to read the request from and + * write the response to. Returns an indication of whether the accept() + * failed, succeeded, or if there were no more connections to accept. + * + * In order to minimize malloc()s, the caller passes in the httpd_conn. + * The caller is also responsible for setting initialized to zero before the + * first call using each different httpd_conn. + */ + +extern int httpd_get_conn(httpd_server *hs, int listen_fd, httpd_conn *hc); + +/* Checks whether the data in hc->read_buf constitutes a complete request + * yet. The caller reads data into hc->read_buf[hc->read_idx] and advances + * hc->read_idx. This routine checks what has been read so far, using + * hc->checked_idx and hc->checked_state to keep track, and returns an + * indication of whether there is no complete request yet, there is a + * complete request, or there won't be a valid request due to a syntax error. + */ + +extern int httpd_got_request(httpd_conn *hc); + +/* Parses the request in hc->read_buf. Fills in lots of fields in hc, + * like the URL and the various headers. + * + * Returns -1 on error. + */ + +extern int httpd_parse_request(httpd_conn *hc); + +/* Starts sending data back to the client. In some cases (directories, + * CGI programs), finishes sending by itself - in those cases, hc->file_fd + * is negative. If there is more data to be sent, then hc->file_fd is a file + * stream for the file to send. If you don't have a current timeval + * handy just pass in 0. + * + * Returns -1 on error. + */ + +extern int httpd_start_request(httpd_conn *hc, struct timeval *nowP); + +/* Actually sends any buffered response text. */ + +extern void httpd_write_response(httpd_conn *hc); + +/* Call this to close down a connection and free the data. */ + +extern void httpd_close_conn(httpd_conn *hc); + +/* Call this to de-initialize a connection struct and *really* free the + * mallocced strings. + */ + +extern void httpd_destroy_conn(httpd_conn *hc); + +/* Send an error message back to the client. */ + +extern void httpd_send_err(httpd_conn *hc, int status, const char *title, + const char *extraheads, const char *form, const char *arg); + +/* Generate a string representation of a method number. */ + +extern const char *httpd_method_str(int method); + +/* Format a network socket to a string representation. */ + +extern char *httpd_ntoa(httpd_sockaddr * saP); + +/* Set NDELAY mode on a socket. */ + +extern void httpd_set_ndelay(int fd); + +/* Clear NDELAY mode on a socket. */ + +extern void httpd_clear_ndelay(int fd); + +/* Read to requested buffer, accounting for interruptions and EOF */ + +extern int httpd_read(int fd, const void *buf, size_t nbytes); + +/* Write the buffer completely, accounting for interruptions */ + +extern int httpd_write(int fd, const void *buf, size_t nbytes); + +#endif /* CONFIG_THTTPD */ +#endif /* __NETUTILS_THTTPD_LIBHTTPD_H */ + diff --git a/apps/netutils/thttpd/mime_types.h b/apps/netutils/thttpd/mime_types.h new file mode 100644 index 000000000..cd0c514a8 --- /dev/null +++ b/apps/netutils/thttpd/mime_types.h @@ -0,0 +1,279 @@ +/**************************************************************************** + * netutils/thttpd/mime_types.h + * Provides mappings between filename extensions and MIME types and encodings. + * + * Based on mime_encodings.txt and mime_types.txt by Jef Poskanser which + * contained no copyright information. + * + * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NETUTILS_THTTPD_MIME_TYPES_H +#define __NETUTILS_THTTPD_MIME_TYPES_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/types.h> + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct mime_entry +{ + char *ext; + size_t ext_len; + char *val; + size_t val_len; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* A list of file extensions followed by the corresponding MIME encoding. + * Extensions not found in the table proceed to the mime_types table. + * Must be ordered by extension so to support binary searches. + */ + +static struct mime_entry enc_tab[] = +{ + { "Z", 0, "compress", 0 }, + { "gz", 0, "gzip", 0 }, + { "uu", 0, "x-uuencode", 0 }, +}; +static const int n_enc_tab = sizeof(enc_tab) / sizeof(*enc_tab); + +/* A list of file extensions followed by the corresponding MIME type. + * Extensions not found in the table are returned as text/plain. + * Must be ordered by extension so to support binary searches. + */ + +static struct mime_entry typ_tab[] = +{ + { "a", 0, "application/octet-stream", 0 }, + { "aab", 0, "application/x-authorware-bin", 0 }, + { "aam", 0, "application/x-authorware-map", 0 }, + { "aas", 0, "application/x-authorware-seg", 0 }, + { "ai", 0, "application/postscript", 0 }, + { "aif", 0, "audio/x-aiff", 0 }, + { "aifc", 0, "audio/x-aiff", 0 }, + { "aiff", 0, "audio/x-aiff", 0 }, + { "asc", 0, "text/plain", 0 }, + { "asf", 0, "video/x-ms-asf", 0 }, + { "asx", 0, "video/x-ms-asf", 0 }, + { "au", 0, "audio/basic", 0 }, + { "avi", 0, "video/x-msvideo", 0 }, + { "bcpio", 0, "application/x-bcpio", 0 }, + { "bin", 0, "application/octet-stream", 0 }, + { "bmp", 0, "image/bmp", 0 }, + { "cdf", 0, "application/x-netcdf", 0 }, + { "class", 0, "application/x-java-vm", 0 }, + { "cpio", 0, "application/x-cpio", 0 }, + { "cpt", 0, "application/mac-compactpro", 0 }, + { "crl", 0, "application/x-pkcs7-crl", 0 }, + { "crt", 0, "application/x-x509-ca-cert", 0 }, + { "csh", 0, "application/x-csh", 0 }, + { "css", 0, "text/css", 0 }, + { "dcr", 0, "application/x-director", 0 }, + { "dir", 0, "application/x-director", 0 }, + { "djv", 0, "image/vnd.djvu", 0 }, + { "djvu", 0, "image/vnd.djvu", 0 }, + { "dll", 0, "application/octet-stream", 0 }, + { "dms", 0, "application/octet-stream", 0 }, + { "doc", 0, "application/msword", 0 }, + { "dtd", 0, "text/xml", 0 }, + { "dump", 0, "application/octet-stream", 0 }, + { "dvi", 0, "application/x-dvi", 0 }, + { "dxr", 0, "application/x-director", 0 }, + { "eps", 0, "application/postscript", 0 }, + { "etx", 0, "text/x-setext", 0 }, + { "exe", 0, "application/octet-stream", 0 }, + { "ez", 0, "application/andrew-inset", 0 }, + { "fgd", 0, "application/x-director", 0 }, + { "fh", 0, "image/x-freehand", 0 }, + { "fh4", 0, "image/x-freehand", 0 }, + { "fh5", 0, "image/x-freehand", 0 }, + { "fh7", 0, "image/x-freehand", 0 }, + { "fhc", 0, "image/x-freehand", 0 }, + { "gif", 0, "image/gif", 0 }, + { "gtar", 0, "application/x-gtar", 0 }, + { "hdf", 0, "application/x-hdf", 0 }, + { "hqx", 0, "application/mac-binhex40", 0 }, + { "htm", 0, "text/html; charset=%s", 0 }, + { "html", 0, "text/html; charset=%s", 0 }, + { "ice", 0, "x-conference/x-cooltalk", 0 }, + { "ief", 0, "image/ief", 0 }, + { "iges", 0, "model/iges", 0 }, + { "igs", 0, "model/iges", 0 }, + { "iv", 0, "application/x-inventor", 0 }, + { "jar", 0, "application/x-java-archive", 0 }, + { "jfif", 0, "image/jpeg", 0 }, + { "jpe", 0, "image/jpeg", 0 }, + { "jpeg", 0, "image/jpeg", 0 }, + { "jpg", 0, "image/jpeg", 0 }, + { "js", 0, "application/x-javascript", 0 }, + { "kar", 0, "audio/midi", 0 }, + { "latex", 0, "application/x-latex", 0 }, + { "lha", 0, "application/octet-stream", 0 }, + { "lzh", 0, "application/octet-stream", 0 }, + { "m3u", 0, "audio/x-mpegurl", 0 }, + { "man", 0, "application/x-troff-man", 0 }, + { "mathml", 0, "application/mathml+xml", 0 }, + { "me", 0, "application/x-troff-me", 0 }, + { "mesh", 0, "model/mesh", 0 }, + { "mid", 0, "audio/midi", 0 }, + { "midi", 0, "audio/midi", 0 }, + { "mif", 0, "application/vnd.mif", 0 }, + { "mime", 0, "message/rfc822", 0 }, + { "mml", 0, "application/mathml+xml", 0 }, + { "mov", 0, "video/quicktime", 0 }, + { "movie", 0, "video/x-sgi-movie", 0 }, + { "mp2", 0, "audio/mpeg", 0 }, + { "mp3", 0, "audio/mpeg", 0 }, + { "mp4", 0, "video/mp4", 0 }, + { "mpe", 0, "video/mpeg", 0 }, + { "mpeg", 0, "video/mpeg", 0 }, + { "mpg", 0, "video/mpeg", 0 }, + { "mpga", 0, "audio/mpeg", 0 }, + { "ms", 0, "application/x-troff-ms", 0 }, + { "msh", 0, "model/mesh", 0 }, + { "mv", 0, "video/x-sgi-movie", 0 }, + { "mxu", 0, "video/vnd.mpegurl", 0 }, + { "nc", 0, "application/x-netcdf", 0 }, + { "o", 0, "application/octet-stream", 0 }, + { "oda", 0, "application/oda", 0 }, + { "ogg", 0, "application/x-ogg", 0 }, + { "pac", 0, "application/x-ns-proxy-autoconfig", 0 }, + { "pbm", 0, "image/x-portable-bitmap", 0 }, + { "pdb", 0, "chemical/x-pdb", 0 }, + { "pdf", 0, "application/pdf", 0 }, + { "pgm", 0, "image/x-portable-graymap", 0 }, + { "pgn", 0, "application/x-chess-pgn", 0 }, + { "png", 0, "image/png", 0 }, + { "pnm", 0, "image/x-portable-anymap", 0 }, + { "ppm", 0, "image/x-portable-pixmap", 0 }, + { "ppt", 0, "application/vnd.ms-powerpoint", 0 }, + { "ps", 0, "application/postscript", 0 }, + { "qt", 0, "video/quicktime", 0 }, + { "ra", 0, "audio/x-realaudio", 0 }, + { "ram", 0, "audio/x-pn-realaudio", 0 }, + { "ras", 0, "image/x-cmu-raster", 0 }, + { "rdf", 0, "application/rdf+xml", 0 }, + { "rgb", 0, "image/x-rgb", 0 }, + { "rm", 0, "audio/x-pn-realaudio", 0 }, + { "roff", 0, "application/x-troff", 0 }, + { "rpm", 0, "audio/x-pn-realaudio-plugin", 0 }, + { "rss", 0, "application/rss+xml", 0 }, + { "rtf", 0, "text/rtf", 0 }, + { "rtx", 0, "text/richtext", 0 }, + { "sgm", 0, "text/sgml", 0 }, + { "sgml", 0, "text/sgml", 0 }, + { "sh", 0, "application/x-sh", 0 }, + { "shar", 0, "application/x-shar", 0 }, + { "silo", 0, "model/mesh", 0 }, + { "sit", 0, "application/x-stuffit", 0 }, + { "skd", 0, "application/x-koan", 0 }, + { "skm", 0, "application/x-koan", 0 }, + { "skp", 0, "application/x-koan", 0 }, + { "skt", 0, "application/x-koan", 0 }, + { "smi", 0, "application/smil", 0 }, + { "smil", 0, "application/smil", 0 }, + { "snd", 0, "audio/basic", 0 }, + { "so", 0, "application/octet-stream", 0 }, + { "spl", 0, "application/x-futuresplash", 0 }, + { "src", 0, "application/x-wais-source", 0 }, + { "stc", 0, "application/vnd.sun.xml.calc.template", 0 }, + { "std", 0, "application/vnd.sun.xml.draw.template", 0 }, + { "sti", 0, "application/vnd.sun.xml.impress.template", 0 }, + { "stw", 0, "application/vnd.sun.xml.writer.template", 0 }, + { "sv4cpio", 0, "application/x-sv4cpio", 0 }, + { "sv4crc", 0, "application/x-sv4crc", 0 }, + { "svg", 0, "image/svg+xml", 0 }, + { "svgz", 0, "image/svg+xml", 0 }, + { "swf", 0, "application/x-shockwave-flash", 0 }, + { "sxc", 0, "application/vnd.sun.xml.calc", 0 }, + { "sxd", 0, "application/vnd.sun.xml.draw", 0 }, + { "sxg", 0, "application/vnd.sun.xml.writer.global", 0 }, + { "sxi", 0, "application/vnd.sun.xml.impress", 0 }, + { "sxm", 0, "application/vnd.sun.xml.math", 0 }, + { "sxw", 0, "application/vnd.sun.xml.writer", 0 }, + { "t", 0, "application/x-troff", 0 }, + { "tar", 0, "application/x-tar", 0 }, + { "tcl", 0, "application/x-tcl", 0 }, + { "tex", 0, "application/x-tex", 0 }, + { "texi", 0, "application/x-texinfo", 0 }, + { "texinfo", 0, "application/x-texinfo", 0 }, + { "tif", 0, "image/tiff", 0 }, + { "tiff", 0, "image/tiff", 0 }, + { "tr", 0, "application/x-troff", 0 }, + { "tsp", 0, "application/dsptype", 0 }, + { "tsv", 0, "text/tab-separated-values", 0 }, + { "txt", 0, "text/plain; charset=%s", 0 }, + { "ustar", 0, "application/x-ustar", 0 }, + { "vcd", 0, "application/x-cdlink", 0 }, + { "vrml", 0, "model/vrml", 0 }, + { "vx", 0, "video/x-rad-screenplay", 0 }, + { "wav", 0, "audio/x-wav", 0 }, + { "wax", 0, "audio/x-ms-wax", 0 }, + { "wbmp", 0, "image/vnd.wap.wbmp", 0 }, + { "wbxml", 0, "application/vnd.wap.wbxml", 0 }, + { "wm", 0, "video/x-ms-wm", 0 }, + { "wma", 0, "audio/x-ms-wma", 0 }, + { "wmd", 0, "application/x-ms-wmd", 0 }, + { "wml", 0, "text/vnd.wap.wml", 0 }, + { "wmlc", 0, "application/vnd.wap.wmlc", 0 }, + { "wmls", 0, "text/vnd.wap.wmlscript", 0 }, + { "wmlsc", 0, "application/vnd.wap.wmlscriptc", 0 }, + { "wmv", 0, "video/x-ms-wmv", 0 }, + { "wmx", 0, "video/x-ms-wmx", 0 }, + { "wmz", 0, "application/x-ms-wmz", 0 }, + { "wrl", 0, "model/vrml", 0 }, + { "wsrc", 0, "application/x-wais-source", 0 }, + { "wvx", 0, "video/x-ms-wvx", 0 }, + { "xbm", 0, "image/x-xbitmap", 0 }, + { "xht", 0, "application/xhtml+xml", 0 }, + { "xhtml", 0, "application/xhtml+xml", 0 }, + { "xls", 0, "application/vnd.ms-excel", 0 }, + { "xml", 0, "text/xml", 0 }, + { "xpm", 0, "image/x-xpixmap", 0 }, + { "xsl", 0, "text/xml", 0 }, + { "xwd", 0, "image/x-xwindowdump", 0 }, + { "xyz", 0, "chemical/x-xyz", 0 }, + { "zip", 0, "application/zip", 0 }, +}; +static const int n_typ_tab = sizeof(typ_tab) / sizeof(*typ_tab); + +#endif /* __NETUTILS_THTTPD_MIME_TYPES_H */ + diff --git a/apps/netutils/thttpd/tdate_parse.c b/apps/netutils/thttpd/tdate_parse.c new file mode 100644 index 000000000..d9ace1b41 --- /dev/null +++ b/apps/netutils/thttpd/tdate_parse.c @@ -0,0 +1,341 @@ +/**************************************************************************** + * netutils/thttpd/timers.c + * Parse string dates into internal form, stripped-down version + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include <debug.h> + +#include "tdate_parse.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#undef TDATE_PARSE_WORKS /* tdate_parse() doesn't work */ +#undef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct strlong +{ + char *s; + long l; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */ +static void pound_case(char *str) +{ + for (; *str != '\0'; ++str) + { + if (isupper((int)*str)) + { + *str = tolower((int)*str); + } + } +} +#endif + +#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */ +static int strlong_compare(const void *v1, const void *v2) +{ + return strcmp(((struct strlong *)v1)->s, ((struct strlong *)v2)->s); +} +#endif + +#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */ +static int strlong_search(char *str, struct strlong *tab, int n, long *lP) +{ + int i, h, l, r; + + l = 0; + h = n - 1; + for (;;) + { + i = (h + l) / 2; + r = strcmp(str, tab[i].s); + if (r < 0) + { + h = i - 1; + } + else if (r > 0) + { + l = i + 1; + } + else + { + *lP = tab[i].l; + return 1; + } + + if (h < l) + { + return 0; + } + } +} +#endif + +#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */ +static int scan_wday(char *str_wday, long *tm_wdayP) +{ + static struct strlong wday_tab[] = { + {"sun", 0}, {"sunday", 0}, + {"mon", 1}, {"monday", 1}, + {"tue", 2}, {"tuesday", 2}, + {"wed", 3}, {"wednesday", 3}, + {"thu", 4}, {"thursday", 4}, + {"fri", 5}, {"friday", 5}, + {"sat", 6}, {"saturday", 6}, + }; + static int sorted = 0; + + if (!sorted) + { + (void)qsort(wday_tab, sizeof(wday_tab) / sizeof(struct strlong), + sizeof(struct strlong), strlong_compare); + sorted = 1; + } + pound_case(str_wday); + return strlong_search(str_wday, wday_tab, + sizeof(wday_tab) / sizeof(struct strlong), tm_wdayP); +} +#endif /* Day of week not yet supported by NuttX */ + +#ifdef TDATE_PARSE_WORKS +static int scan_mon(char *str_mon, long *tm_monP) +{ + static struct strlong mon_tab[] = { + {"jan", 0}, {"january", 0}, + {"feb", 1}, {"february", 1}, + {"mar", 2}, {"march", 2}, + {"apr", 3}, {"april", 3}, + {"may", 4}, + {"jun", 5}, {"june", 5}, + {"jul", 6}, {"july", 6}, + {"aug", 7}, {"august", 7}, + {"sep", 8}, {"september", 8}, + {"oct", 9}, {"october", 9}, + {"nov", 10}, {"november", 10}, + {"dec", 11}, {"december", 11}, + }; + static int sorted = 0; + + if (!sorted) + { + (void)qsort(mon_tab, sizeof(mon_tab) / sizeof(struct strlong), + sizeof(struct strlong), strlong_compare); + sorted = 1; + } + pound_case(str_mon); + return strlong_search(str_mon, mon_tab, + sizeof(mon_tab) / sizeof(struct strlong), tm_monP); +} +#endif +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +time_t tdate_parse(char *str) +{ +#ifdef TDATE_PARSE_WORKS /* REVISIT -- doesn't work */ + struct tm tm; + char *cp; + char str_mon[32]; + int tm_year; + int tm_mday; + int tm_hour; + int tm_min; + int tm_sec; + long tm_mon; +#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */ + char str_wday[32]; + long tm_wday; +#endif + + nvdbg("str: \"%s\"\n", str); + + /* Initialize. */ + + (void)memset((char *)&tm, 0, sizeof(struct tm)); + + /* Skip initial whitespace ourselves - sscanf is clumsy at this. */ + + for (cp = str; *cp == ' ' || *cp == '\t'; ++cp) + { + continue; + } + + /* And do the sscanfs. WARNING: you can add more formats here, but be + * careful! You can easily screw up the parsing of existing formats when + * you add new ones. The order is important. */ + + /* DD-mth-YY HH:MM:SS GMT */ + if (sscanf(cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT", + &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, + &tm_sec) == 6 && scan_mon(str_mon, &tm_mon)) + { + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + } + + /* DD mth YY HH:MM:SS GMT */ + else if (sscanf(cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT", + &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, + &tm_sec) == 6 && scan_mon(str_mon, &tm_mon)) + { + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + } + + /* HH:MM:SS GMT DD-mth-YY */ + else if (sscanf(cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d", + &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon, + &tm_year) == 6 && scan_mon(str_mon, &tm_mon)) + { + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + } + + /* HH:MM:SS GMT DD mth YY */ + else if (sscanf(cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d", + &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon, + &tm_year) == 6 && scan_mon(str_mon, &tm_mon)) + { + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + } + +#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */ + /* wdy, DD-mth-YY HH:MM:SS GMT */ + else if (sscanf(cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT", + str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, + &tm_sec) == 7 && + scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon)) + { + tm.tm_wday = tm_wday; + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + } +#endif /* Day of week not yet supported by NuttX */ + +#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */ + /* wdy, DD mth YY HH:MM:SS GMT */ + else if (sscanf(cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT", + str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, + &tm_sec) == 7 && + scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon)) + { + tm.tm_wday = tm_wday; + tm.tm_mday = tm_mday; + tm.tm_mon = tm_mon; + tm.tm_year = tm_year; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + } +#endif /* Day of week not yet supported by NuttX */ + +#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */ + /* wdy mth DD HH:MM:SS GMT YY */ + else if (sscanf(cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d", + str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec, + &tm_year) == 7 && + scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon)) + { + tm.tm_wday = tm_wday; + tm.tm_mon = tm_mon; + tm.tm_mday = tm_mday; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + tm.tm_year = tm_year; + } +#endif /* Day of week not yet supported by NuttX */ + else + { + return (time_t) - 1; + } + + if (tm.tm_year > 1900) + { + tm.tm_year -= 1900; + } + else if (tm.tm_year < 70) + { + tm.tm_year += 100; + } + + return mktime(&tm); +#else + return 0; // for now +#endif +} + diff --git a/apps/netutils/thttpd/tdate_parse.h b/apps/netutils/thttpd/tdate_parse.h new file mode 100644 index 000000000..301d5467a --- /dev/null +++ b/apps/netutils/thttpd/tdate_parse.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * netutils/thttpd/fdwatch.h + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in THTTPD: + * + * Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NETUTILS_TDATE_PARSE_H +#define __NETUTILS_TDATE_PARSE_H + +extern time_t tdate_parse(char *str); + +#endif /* __NETUTILS_TDATE_PARSE_H */ diff --git a/apps/netutils/thttpd/thttpd.c b/apps/netutils/thttpd/thttpd.c new file mode 100644 index 000000000..3b49c0141 --- /dev/null +++ b/apps/netutils/thttpd/thttpd.c @@ -0,0 +1,861 @@ +/**************************************************************************** + * netutils/thttpd/thttpd.c + * Tiny HTTP Server + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <signal.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/compiler.h> +#include <nuttx/symtab.h> +#include <apps/netutils/thttpd.h> + +#include "config.h" +#include "fdwatch.h" +#include "libhttpd.h" +#include "thttpd_alloc.h" +#include "thttpd_strings.h" +#include "timers.h" + +#ifdef CONFIG_THTTPD + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef MAXPATHLEN +# define MAXPATHLEN 64 +#endif + +/* The connection states */ + +#define CNST_FREE 0 +#define CNST_READING 1 +#define CNST_SENDING 2 +#define CNST_LINGERING 3 + +#define SPARE_FDS 2 +#define AVAILABLE_FDS (CONFIG_NSOCKET_DESCRIPTORS - SPARE_FDS) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct connect_s +{ + struct connect_s *next; + int conn_state; + httpd_conn *hc; + time_t active_at; + Timer *wakeup_timer; + Timer *linger_timer; + off_t end_offset; /* The final offset+1 of the file to send */ + off_t offset; /* The current offset into the file to send */ + bool eof; /* Set true when length==0 read from file */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static httpd_server *hs; +static struct connect_s *free_connections; +static struct connect_s *connects; +static struct fdwatch_s *fw; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void shut_down(void); +static int handle_newconnect(struct timeval *tv, int listen_fd); +static void handle_read(struct connect_s *conn, struct timeval *tv); +static void handle_send(struct connect_s *conn, struct timeval *tv); +static void handle_linger(struct connect_s *conn, struct timeval *tv); +static void finish_connection(struct connect_s *conn, struct timeval *tv); +static void clear_connection(struct connect_s *conn, struct timeval *tv); +static void really_clear_connection(struct connect_s *conn); +static void idle(ClientData client_data, struct timeval *nowP); +static void linger_clear_connection(ClientData client_data, struct timeval *nowP); +static void occasional(ClientData client_data, struct timeval *nowP); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void shut_down(void) +{ + int cnum; + + for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum) + { + if (connects[cnum].conn_state != CNST_FREE) + { + httpd_close_conn(connects[cnum].hc); + } + + if (connects[cnum].hc != NULL) + { + httpd_destroy_conn(connects[cnum].hc); + httpd_free((void *)connects[cnum].hc); + connects[cnum].hc = NULL; + } + } + + if (hs) + { + httpd_server *ths = hs; + hs = NULL; + if (ths->listen_fd != -1) + { + fdwatch_del_fd(fw, ths->listen_fd); + } + httpd_terminate(ths); + } + + tmr_destroy(); + httpd_free((void *)connects); +} + +static int handle_newconnect(struct timeval *tv, int listen_fd) +{ + struct connect_s *conn; + ClientData client_data; + + /* This loops until the accept() fails, trying to start new connections as + * fast as possible so we don't overrun the listen queue. + */ + + nvdbg("New connection(s) on listen_fd %d\n", listen_fd); + for (;;) + { + /* Get the next free connection from the free list */ + + conn = free_connections; + + /* Are there any free connections? */ + + if (!conn) + { + /* Out of connection slots. Run the timers, then the existing + * connections, and maybe we'll free up a slot by the time we get + * back here. + */ + + ndbg("No free connections\n"); + tmr_run(tv); + return -1; + } + + /* Make the httpd_conn if necessary */ + + if (!conn->hc) + { + conn->hc = NEW(httpd_conn, 1); + if (conn->hc == NULL) + { + ndbg("out of memory allocating an httpd_conn\n"); + exit(1); + } + + conn->hc->initialized = 0; + } + + /* Get the connection */ + + switch (httpd_get_conn(hs, listen_fd, conn->hc)) + { + /* Some error happened. Run the timers, then the existing + * connections. Maybe the error will clear. + */ + + case GC_FAIL: + tmr_run(tv); + return -1; + + /* No more connections to accept for now */ + + case GC_NO_MORE: + return 0; + + default: + break; + } + + nvdbg("New connection fd %d\n", conn->hc->conn_fd); + + /* Remove the connection entry from the free list */ + + conn->conn_state = CNST_READING; + free_connections = conn->next; + conn->next = NULL; + + client_data.p = conn; + conn->active_at = tv->tv_sec; + conn->wakeup_timer = NULL; + conn->linger_timer = NULL; + conn->offset = 0; + + /* Set the connection file descriptor to no-delay mode */ + + httpd_set_ndelay(conn->hc->conn_fd); + fdwatch_add_fd(fw, conn->hc->conn_fd, conn); + } +} + +static void handle_read(struct connect_s *conn, struct timeval *tv) +{ + ClientData client_data; + httpd_conn *hc = conn->hc; + off_t actual; + int sz; + + /* Is there room in our buffer to read more bytes? */ + + if (hc->read_idx >= hc->read_size) + { + if (hc->read_size > CONFIG_THTTPD_MAXREALLOC) + { + BADREQUEST("MAXREALLOC"); + goto errout_with_400; + } + httpd_realloc_str(&hc->read_buf, &hc->read_size, hc->read_size + CONFIG_THTTPD_REALLOCINCR); + } + + /* Read some more bytes */ + + sz = read(hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx); + if (sz == 0) + { + BADREQUEST("EOF"); + goto errout_with_400; + } + + if (sz < 0) + { + /* Ignore EINTR and EAGAIN. Also ignore EWOULDBLOCK. At first glance + * you would think that connections returned by fdwatch as readable + * should never give an EWOULDBLOCK; however, this apparently can + * happen if a packet gets garbled. + */ + + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) + { + return; + } + + ndbg("read(fd=%d) failed: %d\n", hc->conn_fd, errno); + BADREQUEST("read"); + goto errout_with_400; + } + + hc->read_idx += sz; + conn->active_at = tv->tv_sec; + + /* Do we have a complete request yet? */ + + switch (httpd_got_request(hc)) + { + case GR_NO_REQUEST: + return; + case GR_BAD_REQUEST: + BADREQUEST("httpd_got_request"); + goto errout_with_400; + } + + /* Yes. Try parsing and resolving it */ + + if (httpd_parse_request(hc) < 0) + { + goto errout_with_connection; + } + + /* Start the connection going */ + + if (httpd_start_request(hc, tv) < 0) + { + /* Something went wrong. Close down the connection */ + + goto errout_with_connection; + } + + /* Set up the file offsets to read */ + + conn->eof = false; + if (hc->got_range) + { + conn->offset = hc->range_start; + conn->end_offset = hc->range_end + 1; + } + else + { + conn->offset = 0; + if (hc->bytes_to_send < 0) + { + conn->end_offset = 0; + } + else + { + conn->end_offset = hc->bytes_to_send; + } + } + + /* Check if it's already handled */ + + if (hc->file_fd < 0) + { + /* No file descriptor means someone else is handling it */ + + conn->offset = hc->bytes_sent; + goto errout_with_connection; + } + + if (conn->offset >= conn->end_offset) + { + /* There's nothing to send */ + + goto errout_with_connection; + } + + /* Seek to the offset of the next byte to send */ + + actual = lseek(hc->file_fd, conn->offset, SEEK_SET); + if (actual != conn->offset) + { + ndbg("fseek to %d failed: offset=%d errno=%d\n", conn->offset, actual, errno); + BADREQUEST("lseek"); + goto errout_with_400; + } + + /* We have a valid connection and a file to send to it */ + + conn->conn_state = CNST_SENDING; + client_data.p = conn; + fdwatch_del_fd(fw, hc->conn_fd); + return; + +errout_with_400: + BADREQUEST("errout"); + httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); + +errout_with_connection: + finish_connection(conn, tv); + return; +} + +static inline int read_buffer(struct connect_s *conn) +{ + httpd_conn *hc = conn->hc; + ssize_t nread = 0; + + if (hc->buflen < CONFIG_THTTPD_IOBUFFERSIZE && !conn->eof) + { + nread = read(hc->file_fd, &hc->buffer[hc->buflen], + CONFIG_THTTPD_IOBUFFERSIZE - hc->buflen); + if (nread == 0) + { + /* Reading zero bytes means we are at the end of file */ + + conn->end_offset = conn->offset; + conn->eof = true; + } + else if (nread > 0) + { + hc->buflen += nread; + } + } + return nread; +} + +static void handle_send(struct connect_s *conn, struct timeval *tv) +{ + httpd_conn *hc = conn->hc; + int nwritten; + int nread; + + /* Read until the entire file is sent -- this could take awhile!! */ + + while (conn->offset < conn->end_offset) + { + nvdbg("offset: %d end_offset: %d bytes_sent: %d\n", + conn->offset, conn->end_offset, conn->hc->bytes_sent); + + /* Fill the rest of the response buffer with file data */ + + nread = read_buffer(conn); + if (nread < 0) + { + ndbg("File read error: %d\n", errno); + goto errout_clear_connection; + } + nvdbg("Read %d bytes, buflen %d\n", nread, hc->buflen); + + /* Send the buffer */ + + if (hc->buflen > 0) + { + /* httpd_write does not return until all bytes have been sent + * (or an error occurs). + */ + + nwritten = httpd_write(hc->conn_fd, hc->buffer, hc->buflen); + if (nwritten < 0) + { + ndbg("Error sending %s: %d\n", hc->encodedurl, errno); + goto errout_clear_connection; + } + + /* We wrote one full buffer of data (httpd_write does not + * return until the full buffer is written (or an error occurs). + */ + + conn->active_at = tv->tv_sec; + hc->buflen = 0; + + /* And update how much of the file we wrote */ + + conn->offset += nwritten; + conn->hc->bytes_sent += nwritten; + nvdbg("Wrote %d bytes\n", nwritten); + } + } + + /* The file transfer is complete -- finish the connection */ + + nvdbg("Finish connection\n"); + finish_connection(conn, tv); + return; + +errout_clear_connection: + ndbg("Clear connection\n"); + clear_connection(conn, tv); + return; +} + +static void handle_linger(struct connect_s *conn, struct timeval *tv) +{ + httpd_conn *hc = conn->hc; + int ret; + + /* In lingering-close mode we just read and ignore bytes. An error or EOF + * ends things, otherwise we go until a timeout + */ + + ret = read(conn->hc->conn_fd, hc->buffer, CONFIG_THTTPD_IOBUFFERSIZE); + if (ret < 0 && (errno == EINTR || errno == EAGAIN)) + { + return; + } + + if (ret <= 0) + { + really_clear_connection(conn); + } +} + +static void finish_connection(struct connect_s *conn, struct timeval *tv) +{ + /* If we haven't actually sent the buffered response yet, do so now */ + + httpd_write_response(conn->hc); + + /* And clear */ + + clear_connection(conn, tv); +} + +static void clear_connection(struct connect_s *conn, struct timeval *tv) +{ + ClientData client_data; + + if (conn->wakeup_timer != NULL) + { + tmr_cancel(conn->wakeup_timer); + conn->wakeup_timer = 0; + } + + /* This is our version of Apache's lingering_close() routine, which is + * their version of the often-broken SO_LINGER socket option. For why + * this is necessary, see http://www.apache.org/docs/misc/fin_wait_2.html + * What we do is delay the actual closing for a few seconds, while reading + * any bytes that come over the connection. However, we don't want to do + * this unless it's necessary, because it ties up a connection slot and + * file descriptor which means our maximum connection-handling rateis + * lower. So, elsewhere we set a flag when we detect the few + * circumstances that make a lingering close necessary. If the flag isn't + * set we do the real close now. + */ + + if (conn->conn_state == CNST_LINGERING) + { + /* If we were already lingering, shut down for real */ + + tmr_cancel(conn->linger_timer); + conn->linger_timer = NULL; + conn->hc->should_linger = false; + } + else if (conn->hc->should_linger) + { + fdwatch_del_fd(fw, conn->hc->conn_fd); + conn->conn_state = CNST_LINGERING; + fdwatch_add_fd(fw, conn->hc->conn_fd, conn); + client_data.p = conn; + + conn->linger_timer = tmr_create(tv, linger_clear_connection, client_data, + CONFIG_THTTPD_LINGER_MSEC, 0); + if (conn->linger_timer != NULL) + { + return; + } + ndbg("tmr_create(linger_clear_connection) failed\n"); + } + + /* Either we are done lingering, we shouldn't linger, or we failed to setup the linger */ + + really_clear_connection(conn); +} + +static void really_clear_connection(struct connect_s *conn) +{ + fdwatch_del_fd(fw, conn->hc->conn_fd); + httpd_close_conn(conn->hc); + if (conn->linger_timer != NULL) + { + tmr_cancel(conn->linger_timer); + conn->linger_timer = 0; + } + + /* Put the connection structure back on the free list */ + + conn->conn_state = CNST_FREE; + conn->next = free_connections; + free_connections = conn; +} + +static void idle(ClientData client_data, struct timeval *nowP) +{ + int cnum; + struct connect_s *conn; + + for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum) + { + conn = &connects[cnum]; + switch (conn->conn_state) + { + case CNST_READING: + if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_READ_LIMIT_SEC) + { + ndbg("%s connection timed out reading\n", httpd_ntoa(&conn->hc->client_addr)); + httpd_send_err(conn->hc, 408, httpd_err408title, "", + httpd_err408form, ""); + finish_connection(conn, nowP); + } + break; + + case CNST_SENDING: + if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC) + { + ndbg("%s connection timed out sending\n", httpd_ntoa(&conn->hc->client_addr)); + clear_connection(conn, nowP); + } + break; + } + } +} + +static void linger_clear_connection(ClientData client_data, struct timeval *nowP) +{ + struct connect_s *conn; + + nvdbg("Clear connection\n"); + conn = (struct connect_s *) client_data.p; + conn->linger_timer = NULL; + really_clear_connection(conn); +} + +static void occasional(ClientData client_data, struct timeval *nowP) +{ + tmr_cleanup(); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: thttpd_main + * + * Description: + * This function is the entrypoint into the THTTPD server. It does not + * return. It may be called, the normal mechanism for starting the server + * is: + * + * 1) Set is g_thttpdsymtab and g_thttpdnsymbols. The user is required + * to provide a symbol table to use for binding CGI programs (if CGI + * is enabled. See examples/nxflat and examples/thttpd for examples of + * how such a symbol table may be created. + * 2) Call task_create() to start thttpd_main() + * + ****************************************************************************/ + +int thttpd_main(int argc, char **argv) +{ + int num_ready; + int cnum; + FAR struct connect_s *conn; + FAR httpd_conn *hc; + httpd_sockaddr sa; + struct timeval tv; +#ifdef CONFIG_THTTPD_DIR + int ret; +#endif + + nvdbg("THTTPD started\n"); + + /* Setup host address */ + +#ifdef CONFIG_NET_IPv6 +# error "IPv6 support not yet implemented" +#else + sa.sin_family = AF_INET; + sa.sin_port = HTONS(CONFIG_THTTPD_PORT); + sa.sin_addr.s_addr = HTONL(CONFIG_THTTPD_IPADDR); +#endif + + /* Initialize the fdwatch package to handle all of the configured + * socket descriptors + */ + + fw = fdwatch_initialize(CONFIG_NSOCKET_DESCRIPTORS); + if (!fw) + { + ndbg("fdwatch initialization failure\n"); + exit(1); + } + + /* Switch directories again if requested */ + +#ifdef CONFIG_THTTPD_DATADIR + if (chdir(CONFIG_THTTPD_DATADIR) < 0) + { + ndbg("chdir to %s: %d\n", CONFIG_THTTPD_DATADIR, errno); + exit(1); + } +#endif + + /* Initialize the timer package */ + + tmr_init(); + + /* Initialize the HTTP layer */ + + nvdbg("Calling httpd_initialize()\n"); + hs = httpd_initialize(&sa); + if (!hs) + { + ndbg("httpd_initialize() failed\n"); + exit(1); + } + + /* Set up the occasional timer */ + + if (tmr_create(NULL, occasional, JunkClientData, CONFIG_THTTPD_OCCASIONAL_MSEC * 1000L, 1) == NULL) + { + ndbg("tmr_create(occasional) failed\n"); + exit(1); + } + + /* Set up the idle timer */ + + if (tmr_create(NULL, idle, JunkClientData, 5 * 1000L, 1) == NULL) + { + ndbg("tmr_create(idle) failed\n"); + exit(1); + + } + + /* Initialize our connections table */ + + connects = NEW(struct connect_s, AVAILABLE_FDS); + if (connects == NULL) + { + ndbg("Out of memory allocating a struct connect_s\n"); + exit(1); + } + + for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum) + { + connects[cnum].conn_state = CNST_FREE; + connects[cnum].next = &connects[cnum + 1]; + connects[cnum].hc = NULL; + } + + connects[AVAILABLE_FDS-1].next = NULL; /* End of link list */ + free_connections = connects; /* Beginning of the link list */ + + if (hs != NULL) + { + if (hs->listen_fd != -1) + { + fdwatch_add_fd(fw, hs->listen_fd, NULL); + } + } + + /* Main loop */ + + nvdbg("Entering the main loop\n"); + (void)gettimeofday(&tv, NULL); + for(;;) + { + /* Do the fd watch */ + + num_ready = fdwatch(fw, tmr_mstimeout(&tv)); + if (num_ready < 0) + { + if (errno == EINTR || errno == EAGAIN) + { + /* Not errors... try again */ + + continue; + } + + ndbg("fdwatch failed: %d\n", errno); + exit(1); + } + + (void)gettimeofday(&tv, NULL); + + if (num_ready == 0) + { + /* No fd's are ready - run the timers */ + + tmr_run(&tv); + continue; + } + + /* Is it a new connection? */ + + if (fdwatch_check_fd(fw, hs->listen_fd)) + { + if (!handle_newconnect(&tv, hs->listen_fd)) + { + /* Go around the loop and do another fdwatch, rather than + * dropping through and processing existing connections. New + * connections always get priority. + */ + + continue; + } + } + + /* Find the connections that need servicing */ + + while ((conn = (struct connect_s*)fdwatch_get_next_client_data(fw)) != (struct connect_s*)-1) + { + if (conn) + { + hc = conn->hc; + if (fdwatch_check_fd(fw, hc->conn_fd)) + { + nvdbg("Handle conn_state %d\n", conn->conn_state); + switch (conn->conn_state) + { + case CNST_READING: + { + handle_read(conn, &tv); + + /* If a GET request was received and a file is ready to + * be sent, then fall through to send the file. + */ + + if (conn->conn_state != CNST_SENDING) + { + break; + } + } + + case CNST_SENDING: + { + /* Send a file -- this really should be performed on a + * separate thread to keep the serve from locking up during + * the write. + */ + + handle_send(conn, &tv); + } + break; + + case CNST_LINGERING: + { + /* Linger close the connection */ + + handle_linger(conn, &tv); + } + break; + } + } + } + } + tmr_run(&tv); + } + + /* The main loop terminated */ + + shut_down(); + ndbg("Exiting\n"); + exit(0); +} + +#endif /* CONFIG_THTTPD */ + diff --git a/apps/netutils/thttpd/thttpd_alloc.c b/apps/netutils/thttpd/thttpd_alloc.c new file mode 100755 index 000000000..71c71397b --- /dev/null +++ b/apps/netutils/thttpd/thttpd_alloc.c @@ -0,0 +1,199 @@ +/**************************************************************************** + * netutils/thttpd/thttpd_alloc.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdlib.h> +#include <debug.h> +#include <errno.h> + +#include "config.h" +#include "thttpd_alloc.h" + +#ifdef CONFIG_THTTPD + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_THTTPD_MEMDEBUG +static int g_nallocations = 0; +static int g_nfreed = 0; +static size_t g_allocated = 0; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Generate debugging statistics */ + +#ifdef CONFIG_THTTPD_MEMDEBUG +void httpd_memstats(void) +{ + static struct mallinfo mm; + + ndbg("%d allocations (%lu bytes), %d freed\n", g_nallocations, (unsigned long)g_allocated, g_nfreed); + + /* Get the current memory usage */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + mm = mallinfo(); +#else + (void)mallinfo(&mm); +#endif + ndbg("arena: %08x ordblks: %08x mxordblk: %08x uordblks: %08x fordblks: %08x\n", + mm.arena, mm.ordblks, mm.mxordblk, mm.uordblks, mm.fordblks); +} +#endif + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +#ifdef CONFIG_THTTPD_MEMDEBUG +FAR void *httpd_malloc(size_t nbytes) +{ + void *ptr = malloc(nbytes); + if (!ptr) + { + ndbg("Allocation of %d bytes failed\n", nbytes); + } + else + { + nvdbg("Allocated %d bytes at %p\n", nbytes, ptr); + g_nallocations++; + g_allocated += nbytes; + } + httpd_memstats(); + return ptr; +} +#endif + +#ifdef CONFIG_THTTPD_MEMDEBUG +FAR void *httpd_realloc(FAR void *oldptr, size_t oldsize, size_t newsize) +{ + void *ptr = realloc(oldptr, newsize); + if (!ptr) + { + ndbg("Re-allocation from %d to %d bytes failed\n", + oldsize, newsize); + } + else + { + nvdbg("Re-allocated form %d to %d bytes (from %p to %p)\n", + oldsize, newsize, oldptr, ptr); + g_allocated += (newsize - oldsize); + } + httpd_memstats(); + return ptr; +} +#endif + +#ifdef CONFIG_THTTPD_MEMDEBUG +void httpd_free(FAR void *ptr) +{ + free(ptr); + g_nfreed++; + nvdbg("Freed memory at %p\n", ptr); + httpd_memstats(); +} +#endif + +#ifdef CONFIG_THTTPD_MEMDEBUG +FAR char *httpd_strdup(const char *str) +{ + FAR char *newstr = strdup(str); + if (!newstr) + { + ndbg("strdup of %s failed\n", str); + } + else + { + nvdbg("strdup'ed %s\n", str); + g_nallocations++; + g_allocated += (strlen(str)+1); + } + httpd_memstats(); + return newstr; +} +#endif + +/* Helpers to implement dynamically allocated strings */ + +void httpd_realloc_str(char **pstr, size_t *maxsize, size_t size) +{ + size_t oldsize; + if (*maxsize == 0) + { + *maxsize = MAX(CONFIG_THTTPD_MINSTRSIZE, size + CONFIG_THTTPD_REALLOCINCR); + *pstr = NEW(char, *maxsize + 1); + } + else if (size > *maxsize) + { + oldsize = *maxsize; + *maxsize = MAX(oldsize * 2, size * 5 / 4); + *pstr = httpd_realloc(*pstr, oldsize + 1, *maxsize + 1); + } + else + { + return; + } + + if (!*pstr) + { + ndbg("out of memory reallocating a string to %d bytes\n", *maxsize); + exit(1); + } +} + +#endif /* CONFIG_THTTPD */ diff --git a/apps/netutils/thttpd/thttpd_alloc.h b/apps/netutils/thttpd/thttpd_alloc.h new file mode 100755 index 000000000..1f24bc2e9 --- /dev/null +++ b/apps/netutils/thttpd/thttpd_alloc.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * netutils/thttpd/thttpd_alloc.h + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NETUTILS_THTTPD_HTTDP_ALLOC_H +#define __NETUTILS_THTTPD_HTTDP_ALLOC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdlib.h> +#include <string.h> +#include "config.h" + +#ifdef CONFIG_THTTPD + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/* Allows all memory management calls to be intercepted */ + +#ifdef CONFIG_THTTPD_MEMDEBUG +extern FAR void *httpd_malloc(size_t nbytes); +extern FAR void *httpd_realloc(FAR void *oldptr, size_t oldsize, size_t newsize); +extern void httpd_free(FAR void *ptr); +extern FAR char *httpd_strdup(const char *str); +#else +# define httpd_malloc(n) malloc(n) +# define httpd_realloc(p,o,n) realloc(p,n) +# define httpd_free(p) free(p) +# define httpd_strdup(s) strdup(s) +#endif + +/* Helpers to support allocations in multiples of a type size */ + +#define NEW(t,n) ((t*)httpd_malloc(sizeof(t)*(n))) +#define RENEW(p,t,o,n) ((t*)httpd_realloc((void*)p, sizeof(t)*(o), sizeof(t)*(n))) + +/* Helpers to implement dynamically allocated strings */ + +extern void httpd_realloc_str(char **pstr, size_t *maxsizeP, size_t size); + +#endif /* CONFIG_THTTPD */ +#endif /* __NETUTILS_THTTPD_HTTDP_ALLOC_H */ diff --git a/apps/netutils/thttpd/thttpd_cgi.c b/apps/netutils/thttpd/thttpd_cgi.c new file mode 100755 index 000000000..3d2eb57b8 --- /dev/null +++ b/apps/netutils/thttpd/thttpd_cgi.c @@ -0,0 +1,1080 @@ +/**************************************************************************** + * netutils/thttpd/thttpd_cgi.c + * CGI support + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file libhttpd.c in the original THTTPD package: + * + * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <libgen.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/symtab.h> +#include <nuttx/binfmt.h> +#include <apps/netutils/thttpd.h> + +#include "config.h" +#include "libhttpd.h" +#include "thttpd_alloc.h" +#include "thttpd_strings.h" +#include "timers.h" +#include "fdwatch.h" + +#if defined(CONFIG_THTTPD) && defined(CONFIG_THTTPD_CGI_PATTERN) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* CONFIG_THTTPD_CGIDUMP will dump the contents of each transfer to and from the CGI task. */ + +#ifdef CONFIG_THTTPD_CGIDUMP +# define cgi_dumpbuffer(m,a,n) lib_dumpbuffer(m,(FAR const uint8_t*)a,n) +#else +# define cgi_dumpbuffer(m,a,n) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum cgi_outbuffer_e +{ + CGI_OUTBUFFER_READHEADER = 0, /* Reading header from HTTP client */ + CGI_OUTBUFFER_HEADERREAD, /* Header has been read */ + CGI_OUTBUFFER_HEADERSENT, /* Header has been sent to the CGI program */ + CGI_OUTBUFFER_READDATA, /* Transferring data from CGI to client */ + CGI_OUTBUFFER_DONE, /* Finished */ +}; + +struct cgi_outbuffer_s +{ + enum cgi_outbuffer_e state; /* State of the transfer */ + char *buffer; /* Allocated I/O buffer */ + size_t size; /* Size of the allocation */ + size_t len; /* Amount of valid data in the allocated buffer */ +}; + +struct cgi_inbuffer_s +{ + int contentlength; /* Size of content to send to CGI task */ + int nbytes; /* Number of bytes sent */ + char buffer[CONFIG_THTTPD_CGIINBUFFERSIZE]; /* Fixed size input buffer */ +}; + +struct cgi_conn_s +{ + /* Descriptors */ + + int connfd; /* Socket connect to CGI client */ + int rdfd; /* Pipe read fd */ + int wrfd; /* Pipe write fd */ + + /* Buffering */ + + struct cgi_outbuffer_s outbuf; /* Dynamically sized output buffer */ + struct cgi_inbuffer_s inbuf; /* Fixed size input buffer */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void create_environment(httpd_conn *hc); +static char **make_argp(httpd_conn *hc); +static inline int cgi_interpose_input(struct cgi_conn_s *cc); +static inline int cgi_interpose_output(struct cgi_conn_s *cc); +static int cgi_child(int argc, char **argv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Used to hold off the main task until the CGI tasks have been configured */ + +static sem_t g_cgisem; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* semaphore helpers */ + +static inline void cgi_semtake(void) +{ + while (sem_wait(&g_cgisem) != 0) + { + /* The only case that an error should occr here is if the wait was\ + * awakened by a signal. + */ + + ASSERT(errno == EINTR); + } +} + +static inline void cgi_semgive(void) +{ + sem_post(&g_cgisem); +} + +/* Set up environment variables. Be real careful here to avoid + * letting malicious clients overrun a buffer. We don't have + * to worry about freeing stuff since we're a sub-task. + */ + +static void create_environment(httpd_conn *hc) +{ + char *cp; + char buf[256]; + + setenv("PATH", CONFIG_THTTPD_CGI_PATH, TRUE); +#ifdef CGI_LD_LIBRARY_PATH + setenv("LD_LIBRARY_PATH", CGI_LD_LIBRARY_PATH, TRUE); +#endif /* CGI_LD_LIBRARY_PATH */ + + setenv("SERVER_SOFTWARE", CONFIG_THTTPD_SERVER_SOFTWARE, TRUE); + + /* If vhosting, use that server-name here. */ +#ifdef CONFIG_THTTPD_VHOST + if (hc->vhostname) + { + cp = hc->vhostname; + } + else +#endif + { + cp = hc->hs->hostname; + } + + if (cp) + { + setenv("SERVER_NAME", cp, TRUE); + } + + setenv("GATEWAY_INTERFACE", "CGI/1.1", TRUE); + setenv("SERVER_PROTOCOL", hc->protocol, TRUE); + + (void)snprintf(buf, sizeof(buf), "%d", (int)CONFIG_THTTPD_PORT); + setenv("SERVER_PORT", buf, TRUE); + + setenv("REQUEST_METHOD", httpd_method_str(hc->method), TRUE); + + if (hc->pathinfo[0] != '\0') + { + char *cp2; + size_t l; + + (void)snprintf(buf, sizeof(buf), "/%s", hc->pathinfo); + setenv("PATH_INFO", buf, TRUE); + + l = strlen(httpd_root) + strlen(hc->pathinfo) + 1; + cp2 = NEW(char, l); + if (cp2) + { + (void)snprintf(cp2, l, "%s%s", httpd_root, hc->pathinfo); + setenv("PATH_TRANSLATED", cp2, TRUE); + } + } + + (void)snprintf(buf, sizeof(buf), "/%s",strcmp(hc->origfilename, ".") == 0 ? "" : hc->origfilename); + setenv("SCRIPT_NAME", buf, TRUE); + + if (hc->query[0] != '\0') + { + setenv("QUERY_STRING", hc->query, TRUE); + } + + setenv("REMOTE_ADDR", httpd_ntoa(&hc->client_addr), TRUE); + if (hc->referer[0] != '\0') + { + setenv("HTTP_REFERER", hc->referer, TRUE); + } + + if (hc->useragent[0] != '\0') + { + setenv("HTTP_USER_AGENT", hc->useragent, TRUE); + } + + if (hc->accept[0] != '\0') + { + setenv("HTTP_ACCEPT", hc->accept, TRUE); + } + + if (hc->accepte[0] != '\0') + { + setenv("HTTP_ACCEPT_ENCODING", hc->accepte, TRUE); + } + + if (hc->acceptl[0] != '\0') + { + setenv("HTTP_ACCEPT_LANGUAGE", hc->acceptl, TRUE); + } + + if (hc->cookie[0] != '\0') + { + setenv("HTTP_COOKIE", hc->cookie, TRUE); + } + + if (hc->contenttype[0] != '\0') + { + setenv("CONTENT_TYPE", hc->contenttype, TRUE); + } + + if (hc->hdrhost[0] != '\0') + { + setenv("HTTP_HOST", hc->hdrhost, TRUE); + } + + if (hc->contentlength != -1) + { + (void)snprintf(buf, sizeof(buf), "%lu", (unsigned long)hc->contentlength); + setenv("CONTENT_LENGTH", buf, TRUE); + } + + if (hc->remoteuser[0] != '\0') + { + setenv("REMOTE_USER", hc->remoteuser, TRUE); + } + + if (hc->authorization[0] != '\0') + { + setenv("AUTH_TYPE", "Basic", TRUE); + } + + /* We only support Basic auth at the moment. */ + + if (getenv("TZ") != NULL) + { + setenv("TZ", getenv("TZ"), TRUE); + } + + setenv("CGI_PATTERN", CONFIG_THTTPD_CGI_PATTERN, TRUE); +} + +/* Set up argument vector */ + +static FAR char **make_argp(httpd_conn *hc) +{ + FAR char **argp; + int argn; + char *cp1; + char *cp2; + + /* By allocating an arg slot for every character in the query, plus one + * for the filename and one for the NULL, we are guaranteed to have + * enough. We could actually use strlen/2. + */ + + argp = NEW(char *, strlen(hc->query) + 2); + if (!argp) + { + return NULL; + } + + argp[0] = strrchr(hc->expnfilename, '/'); + if (argp[0]) + { + ++argp[0]; + } + else + { + argp[0] = hc->expnfilename; + } + argn = 1; + + /* According to the CGI spec at http://hoohoo.ncsa.uiuc.edu/cgi/cl.html, + * "The server should search the query information for a non-encoded = + * character to determine if the command line is to be used, if it finds + * one, the command line is not to be used." + */ + + if (strchr(hc->query, '=') == NULL) + { + for (cp1 = cp2 = hc->query; *cp2 != '\0'; ++cp2) + { + if (*cp2 == '+') + { + *cp2 = '\0'; + httpd_strdecode(cp1, cp1); + argp[argn++] = cp1; + cp1 = cp2 + 1; + } + } + + if (cp2 != cp1) + { + httpd_strdecode(cp1, cp1); + argp[argn++] = cp1; + } + } + + argp[argn] = NULL; + return argp; +} + +/* Data is available from the client socket. This routine is used only for POST + * requests. It reads the data from the client and sends it to the child thread. + */ + +static inline int cgi_interpose_input(struct cgi_conn_s *cc) +{ + ssize_t nbytes_read; + ssize_t nbytes_written; + + nllvdbg("nbytes: %d contentlength: %d\n", cc->inbuf.nbytes, cc->inbuf.contentlength); + if (cc->inbuf.nbytes < cc->inbuf.contentlength) + { + do + { + nbytes_read = read(cc->connfd, cc->inbuf.buffer, + MIN(CONFIG_THTTPD_CGIINBUFFERSIZE, cc->inbuf.contentlength - cc->inbuf.nbytes)); + nllvdbg("nbytes_read: %d\n", nbytes_read); + if (nbytes_read < 0) + { + if (errno != EINTR) + { + nlldbg("read failed: %d\n", errno); + return 1; + } + } + } + while (nbytes_read < 0); + + if (nbytes_read > 0) + { + nbytes_written = httpd_write(cc->wrfd, cc->inbuf.buffer, nbytes_read); + nllvdbg("nbytes_written: %d\n", nbytes_written); + if (nbytes_written != nbytes_read) + { + nlldbg("httpd_write failed\n"); + return 1; + } + cgi_dumpbuffer("Sent to CGI:", cc->inbuf.buffer, nbytes_written); + } + + cc->inbuf.nbytes += nbytes_read; + } + + if (cc->inbuf.nbytes >= cc->inbuf.contentlength) + { + /* Special hack to deal with broken browsers that send a LF or CRLF + * after POST data, causing TCP resets - we just read and discard up + * to 2 bytes. Unfortunately this doesn't fix the problem for CGIs + * which avoid the interposer task due to their POST data being + * short. Creating an interposer task for all POST CGIs is + * unacceptably expensive. The eventual fix will come when interposing + * gets integrated into the main loop as a tasklet instead of a task. + */ + + /* Turn on no-delay mode in case we previously cleared it. */ + + httpd_set_ndelay(cc->connfd); + + /* And read up to 2 bytes. */ + + (void)read(cc->connfd, cc->inbuf.buffer, CONFIG_THTTPD_CGIINBUFFERSIZE); + return 1; + } + return 0; +} + +/* This routine is used for parsed-header CGIs. The idea here is that the + * CGI can return special headers such as "Status:" and "Location:" which + * change the return status of the response. Since the return status has to + * be the very first line written out, we have to accumulate all the headers + * and check for the special ones before writing the status. Then we write + * out the saved headers and proceed to echo the rest of the response. + */ + +static inline int cgi_interpose_output(struct cgi_conn_s *cc) +{ + ssize_t nbytes_read; + char *br = NULL; + int status; + const char *title; + char *cp; + + /* Make sure the connection is in blocking mode. It should already be + * blocking, but we might as well be sure. + */ + + httpd_clear_ndelay(cc->connfd); + + /* Loop while there are things we can do without waiting for more input */ + + nllvdbg("state: %d\n", cc->outbuf.state); + switch (cc->outbuf.state) + { + case CGI_OUTBUFFER_READHEADER: + { + /* Slurp in all headers as they become available from the client. */ + + do + { + /* Read until we successfully read data or until an error occurs. + * EAGAIN is not an error, but it is still cause to return. + */ + + nbytes_read = read(cc->rdfd, cc->inbuf.buffer, CONFIG_THTTPD_CGIINBUFFERSIZE); + nllvdbg("Read %d bytes from fd %d\n", nbytes_read, cc->rdfd); + + if (nbytes_read < 0) + { + if (errno != EINTR) + { + if (errno != EAGAIN) + { + nlldbg("read: %d\n", errno); + } + return 1; + } + } + else + { + cgi_dumpbuffer("Received from CGI:", cc->inbuf.buffer, nbytes_read); + } + } + while (nbytes_read < 0); + + /* Check for end-of-file */ + + if (nbytes_read <= 0) + { + nllvdbg("End-of-file\n"); + br = &(cc->outbuf.buffer[cc->outbuf.len]); + cc->outbuf.state = CGI_OUTBUFFER_HEADERREAD; + } + else + { + /* Accumulate more header data */ + + httpd_realloc_str(&cc->outbuf.buffer, &cc->outbuf.size, cc->outbuf.len + nbytes_read); + (void)memcpy(&(cc->outbuf.buffer[cc->outbuf.len]), cc->inbuf.buffer, nbytes_read); + cc->outbuf.len += nbytes_read; + cc->outbuf.buffer[cc->outbuf.len] = '\0'; + nllvdbg("Header bytes accumulated: %d\n", cc->outbuf.len); + + /* Check for end of header */ + + if ((br = strstr(cc->outbuf.buffer, "\r\n\r\n")) != NULL || + (br = strstr(cc->outbuf.buffer, "\012\012")) != NULL) + { + nllvdbg("End-of-header\n"); + cc->outbuf.state = CGI_OUTBUFFER_HEADERREAD; + } + else + { + /* All of the headers have not yet been read ... Return. We + * will be called again when more data is available in the pipe + * connected to the CGI task. + */ + + return 0; + } + } + } + + /* Otherwise, fall through and parse status in the HTTP headers */ + + case CGI_OUTBUFFER_HEADERREAD: + { + /* If there were no headers, bail. */ + + if (cc->outbuf.buffer[0] == '\0') + { + cc->outbuf.state = CGI_OUTBUFFER_DONE; + return 1; + } + + /* Figure out the status. Look for a Status: or Location: header; else if + * there's an HTTP header line, get it from there; else default to 200. + */ + + status = 200; + if (strncmp(cc->outbuf.buffer, "HTTP/", 5) == 0) + { + cp = cc->outbuf.buffer; + cp += strcspn(cp, " \t"); + status = atoi(cp); + } + + if ((cp = strstr(cc->outbuf.buffer, "Status:")) != NULL && + cp < br && (cp == cc->outbuf.buffer || *(cp - 1) == '\012')) + { + cp += 7; + cp += strspn(cp, " \t"); + status = atoi(cp); + } + + if ((cp = strstr(cc->outbuf.buffer, "Location:")) != NULL && + cp < br && (cp == cc->outbuf.buffer || *(cp - 1) == '\012')) + { + status = 302; + } + + /* Write the status line. */ + + nllvdbg("Status: %d\n", status); + switch (status) + { + case 200: + title = ok200title; + break; + + case 302: + title = err302title; + break; + + case 304: + title = err304title; + break; + + case 400: + BADREQUEST("status"); + title = httpd_err400title; + break; + +#ifdef CONFIG_THTTPD_AUTH_FILE + case 401: + title = err401title; + break; +#endif + + case 403: + title = err403title; + break; + + case 404: + title = err404title; + break; + + case 408: + title = httpd_err408title; + break; + + case 500: + INTERNALERROR("status"); + title = err500title; + break; + + case 501: + NOTIMPLEMENTED("status"); + title = err501title; + break; + + case 503: + title = httpd_err503title; + break; + + default: + title = "Something"; + break; + } + + (void)snprintf(cc->inbuf.buffer, CONFIG_THTTPD_CGIINBUFFERSIZE, "HTTP/1.0 %d %s\r\n", status, title); + (void)httpd_write(cc->connfd, cc->inbuf.buffer, strlen(cc->inbuf.buffer)); + + /* Write the saved cc->outbuf.buffer to the client. */ + + (void)httpd_write(cc->connfd, cc->outbuf.buffer, cc->outbuf.len); + } + + /* Then set up to read the data following the header from the CGI program and + * pass it back to the client. We return now; we will be called again when + * data is available on the pipe. + */ + + cc->outbuf.state = CGI_OUTBUFFER_READDATA; + return 0; + + case CGI_OUTBUFFER_READDATA: + { + /* Read data from the pipe. */ + + do + { + /* Read until we successfully read data or until an error occurs. + * EAGAIN is not an error, but it is still cause to return. + */ + + nbytes_read = read(cc->rdfd, cc->inbuf.buffer, CONFIG_THTTPD_CGIINBUFFERSIZE); + nllvdbg("Read %d bytes from fd %d\n", nbytes_read, cc->rdfd); + + if (nbytes_read < 0) + { + if (errno != EINTR) + { + if (errno != EAGAIN) + { + nlldbg("read: %d\n", errno); + } + return 1; + } + } + else + { + cgi_dumpbuffer("Received from CGI:", cc->inbuf.buffer, nbytes_read); + } + } + while (nbytes_read < 0); + + /* Check for end of file */ + + if (nbytes_read == 0) + { + nllvdbg("End-of-file\n"); + cc->outbuf.state = CGI_OUTBUFFER_DONE; + return 1; + } + else + { + /* Forward the data from the CGI program to the client */ + + (void)httpd_write(cc->connfd, cc->inbuf.buffer, nbytes_read); + } + } + break; + + case CGI_OUTBUFFER_DONE: + default: + return 1; + } + return 0; +} + +/* CGI child task. */ + +static int cgi_child(int argc, char **argv) +{ + FAR httpd_conn *hc = (FAR httpd_conn*)strtoul(argv[1], NULL, 16); +#if CONFIG_THTTPD_CGI_TIMELIMIT > 0 + ClientData client_data; +#endif + FAR char **argp; + FAR struct cgi_conn_s *cc; + FAR struct fdwatch_s *fw; + FAR char *directory; + FAR char *dupname; + bool indone; + bool outdone; + int child; + int pipefd[2]; + int nbytes; + int fd; + int ret; + int err = 1; + + /* Use low-level debug out (because the low-level output may survive closing + * all file descriptors + */ + + nllvdbg("Started: %s\n", argv[1]); + + /* Allocate memory and initialize memory for interposing */ + + cc = (FAR struct cgi_conn_s*)httpd_malloc(sizeof(struct cgi_conn_s)); + if (!cc) + { + nlldbg("cgi_conn allocation failed\n"); + close(hc->conn_fd); + goto errout; + } + + cc->connfd = hc->conn_fd; + cc->wrfd = -1; + cc->rdfd = -1; + memset(&cc->outbuf, 0, sizeof(struct cgi_outbuffer_s)); + + /* Update all of the environment variable settings, these will be inherited + * by the CGI task. + */ + + create_environment(hc); + + /* Make the argument vector. */ + + argp = make_argp(hc); + + /* Close all file descriptors EXCEPT for stdin, stdout, stderr and + * hc->conn_fd. We'll keep stderr open for error reporting; stdin and + * stdout will be closed later by dup2(). Keeping stdin and stdout open + * now prevents re-use of fd=0 and 1 by pipe(). + */ + + nllvdbg("Closing descriptors\n"); + for (fd = 3; fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS); fd++) + { + /* Keep hc->conn_fd open for obvious reasons */ + + if (fd != hc->conn_fd) + { + close(fd); + } + } + + /* Create pipes that will be interposed between the CGI task's stdin or + * stdout and the socket. + * + * Setup up the STDIN pipe - a pipe to transfer data received on the + * socket to the CGI program. + */ + + nllvdbg("Create STDIN pipe\n"); + ret = pipe(pipefd); + if (ret < 0) + { + nlldbg("STDIN pipe: %d\n", errno); + goto errout_with_cgiconn; + } + else + { + /* Then map the receiving end the pipe to stdin, save the sending end, and + * closing the original receiving end + */ + + ret = dup2(pipefd[0], 0); + + cc->wrfd = pipefd[1]; + close(pipefd[0]); + + if (ret < 0) + { + nlldbg("STDIN dup2: %d\n", errno); + goto errout_with_descriptors; + } + } + + /* Set up the STDOUT pipe - a pipe to transfer data received from the CGI program + * to the client. + */ + + if (ret == 0) + { + nllvdbg("Create STDOUT pipe\n"); + ret = pipe(pipefd); + if (ret < 0) + { + nlldbg("STDOUT pipe: %d\n", errno); + goto errout_with_descriptors; + } + else + { + /* Then map the sending end the pipe to stdout, save the receiving end, and + * closing the original sending end + */ + + ret = dup2(pipefd[1], 1); + + cc->rdfd = pipefd[0]; + close(pipefd[1]); + + if (ret < 0) + { + nlldbg("STDOUT dup2: %d\n", errno); + goto errout_with_descriptors; + } + } + } + + /* chdir to the directory containing the binary. This isn't in the CGI 1.1 + * spec, but it's what other HTTP servers do. + */ + + dupname = httpd_strdup(hc->expnfilename); + if (dupname) + { + directory = dirname(dupname); + if (directory) + { + (void)chdir(directory); /* ignore errors */ + } + httpd_free(dupname); + } + + /* Allocate memory for output buffering */ + + httpd_realloc_str(&cc->outbuf.buffer, &cc->outbuf.size, CONFIG_THTTPD_CGIOUTBUFFERSIZE); + if (!cc->outbuf.buffer) + { + nlldbg("hdr allocation failed\n"); + goto errout_with_descriptors; + } + + /* Create fdwatch structures */ + + fw = fdwatch_initialize(2); + if (!fw) + { + nlldbg("fdwatch allocation failed\n"); + goto errout_with_outbuffer; + } + + /* Run the CGI program. */ + + nllvdbg("Starting CGI: %s\n", hc->expnfilename); + child = exec(hc->expnfilename, (FAR const char **)argp, g_thttpdsymtab, g_thttpdnsymbols); + if (child < 0) + { + /* Something went wrong. */ + + nlldbg("execve %s: %d\n", hc->expnfilename, errno); + goto errout_with_watch; + } + + /* Schedule a kill for the child task in case it runs too long. */ + +#if CONFIG_THTTPD_CGI_TIMELIMIT > 0 + client_data.i = child; + if (tmr_create(NULL, cgi_kill, client_data, CONFIG_THTTPD_CGI_TIMELIMIT * 1000L, 0) == NULL) + { + nlldbg("tmr_create(cgi_kill child) failed\n"); + goto errout_with_watch; + } +#endif + + /* Add the read descriptors to the watch */ + + fdwatch_add_fd(fw, cc->connfd, NULL); + fdwatch_add_fd(fw, cc->rdfd, NULL); + + /* Send any data that is already buffer to the CGI task */ + + nbytes = hc->read_idx - hc->checked_idx; + nllvdbg("nbytes: %d contentlength: %d\n", nbytes, hc->contentlength); + if (nbytes > 0) + { + if (httpd_write(cc->wrfd, &(hc->read_buf[hc->checked_idx]), nbytes) != nbytes) + { + nlldbg("httpd_write failed\n"); + return 1; + } + } + + cc->inbuf.contentlength = hc->contentlength; + cc->inbuf.nbytes = nbytes; + + /* Then perform the interposition */ + + indone = false; + outdone = false; + + nllvdbg("Interposing\n"); + cgi_semgive(); /* Not safe to reference hc after this point */ + do + { + (void)fdwatch(fw, 1000); + + /* Check for incoming data from the remote client to the CGI task */ + + if (!indone && fdwatch_check_fd(fw, cc->connfd)) + { + /* Transfer data from the client to the CGI program (POST) */ + + nllvdbg("Interpose input\n"); + indone = cgi_interpose_input(cc); + if (indone) + { + fdwatch_del_fd(fw, cc->connfd); + } + } + + /* Check for outgoing data from the CGI task to the remote client */ + + if (fdwatch_check_fd(fw, cc->rdfd)) + { + /* Handle receipt of headers and CGI program response (GET) */ + + nllvdbg("Interpose output\n"); + outdone = cgi_interpose_output(cc); + } + + /* No outgoing data... is the child task still running? Use kill() + * kill() with signal number == 0 does not actually send a signal, but + * can be used to check if the target task exists. If the task exists + * but is hung, then you might enable CONFIG_THTTPD_CGI_TIMELIMIT to + * kill the task. However, killing the task could cause other problems + * (consider resetting the microprocessor instead). + */ + + else if (kill(child, 0) != 0) + { + nllvdbg("CGI no longer running: %d\n", errno); + outdone = true; + } + } + while (!outdone); + err = 0; + + /* Get rid of watch structures */ + +errout_with_watch: + fdwatch_uninitialize(fw); + + /* Free output buffer memory */ + +errout_with_outbuffer: + httpd_free(cc->outbuf.buffer); + + /* Close all descriptors */ + +errout_with_descriptors: + close(cc->wrfd); + close(cc->rdfd); + +errout_with_cgiconn: + close(cc->connfd); + httpd_free(cc); + +errout: + nllvdbg("Return %d\n", err); + if (err != 0) + { + INTERNALERROR("errout"); + httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); + httpd_write_response(hc); + cgi_semgive(); + } + return err; +} + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +int cgi(httpd_conn *hc) +{ + char arg[16]; + char *argv[1]; + pid_t child; + int retval = ERROR; + + /* Set up a semaphore to hold off the make THTTPD thread until the CGI + * threads are configured (basically until the file descriptors are all + * dup'ed and can be closed by the main thread). + */ + + sem_init(&g_cgisem, 0, 0); + + if (hc->method == METHOD_GET || hc->method == METHOD_POST) + { +#ifdef CONFIG_THTTPD_CGILIMIT + if (hc->hs->cgi_count >= CONFIG_THTTPD_CGILIMIT) + { + httpd_send_err(hc, 503, httpd_err503title, "", httpd_err503form, + hc->encodedurl); + goto errout_with_sem; + } +#endif + ++hc->hs->cgi_count; + httpd_clear_ndelay(hc->conn_fd); + + /* Start the child task. We use a trampoline task here so that we can + * safely muck with the file descriptors before actually started the CGI + * task. + */ + + snprintf(arg, 16, "%p", hc); /* task_create doesn't handle binary arguments. */ + argv[0] = arg; + +#ifndef CONFIG_CUSTOM_STACK + child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY, + CONFIG_THTTPD_CGI_STACKSIZE, + (main_t)cgi_child, (const char **)argv); +#else + child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY, + (main_t)cgi_child, (const char **)argv); +#endif + if (child < 0) + { + ndbg("task_create: %d\n", errno); + INTERNALERROR("task_create"); + httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl); + goto errout_with_sem; + } + + ndbg("Started CGI task %d for file '%s'\n", child, hc->expnfilename); + + /* Wait for the CGI threads to become initialized */ + + cgi_semtake(); + + hc->bytes_sent = CONFIG_THTTPD_CGI_BYTECOUNT; + hc->should_linger = false; + } + else + { + NOTIMPLEMENTED("CGI"); + httpd_send_err(hc, 501, err501title, "", err501form, httpd_method_str(hc->method)); + goto errout_with_sem; + } + + /* Successfully started */ + + retval = OK; + +errout_with_sem: + sem_destroy(&g_cgisem); + return retval; +} + +#if CONFIG_THTTPD_CGI_TIMELIMIT > 0 +static void cgi_kill(ClientData client_data, struct timeval *nowP) +{ + pid_t pid = (pid_t)client_data.i; + + /* task_delete() is a very evil API. It can leave memory stranded! */ + + nlldbg("Killing CGI child: %d\n", pid); + if (task_delete(pid) != 0) + { + nlldbg("task_delete() failed: %d\n", errno); + } +} +#endif + +#endif /* CONFIG_THTTPD && CONFIG_THTTPD_CGI_PATTERN */ + diff --git a/apps/netutils/thttpd/thttpd_cgi.h b/apps/netutils/thttpd/thttpd_cgi.h new file mode 100755 index 000000000..2d98e25ec --- /dev/null +++ b/apps/netutils/thttpd/thttpd_cgi.h @@ -0,0 +1,61 @@ +/****************************************************************************
+ * netutils/thttpd/thttpd_cgi.h
+ * CGI support
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file libhttpd.c in the original THTTPD package:
+ *
+ * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __HTTPD_CGI_H
+#define __HTTPD_CGI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "config.h"
+#include "libhttpd.h"
+
+#if defined(CONFIG_THTTPD) && defined(CONFIG_THTTPD_CGI_PATTERN)
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+extern int cgi(httpd_conn *hc);
+#if CONFIG_THTTPD_CGI_TIMELIMIT > 0
+static void cgi_kill(ClientData client_data, struct timeval *now);
+#endif
+
+#endif /* CONFIG_THTTPD && CONFIG_THTTPD_CGI_PATTERN */
+#endif /* __HTTPD_CGI_H */
diff --git a/apps/netutils/thttpd/thttpd_strings.c b/apps/netutils/thttpd/thttpd_strings.c new file mode 100755 index 000000000..82836ee99 --- /dev/null +++ b/apps/netutils/thttpd/thttpd_strings.c @@ -0,0 +1,179 @@ +/****************************************************************************
+ * netutils/thttpd/thttpd_strings.c
+ * HTTP strings
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in the original THTTPD package:
+ *
+ * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "thttpd_strings.h"
+
+#ifdef CONFIG_THTTPD
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* This is the 'root' of the Filesystem as seen by the HTTP client */
+
+const char httpd_root[] = CONFIG_THTTPD_PATH;
+
+/* HTPP status */
+
+const char ok200title[] = "OK";
+const char ok206title[] = "Partial Content";
+
+const char err302title[] = "Found";
+const char err302form[] = "The actual URL is '%s'.\n";
+
+const char err304title[] = "Not Modified";
+
+const char httpd_err400title[] = "Bad Request";
+const char httpd_err400form[] = "Your request has bad syntax or is inherently impossible to satisfy.\n";
+
+#ifdef CONFIG_THTTPD_AUTH_FILE
+const char err401title[] = "Unauthorized";
+const char err401form[] = "Authorization required for the URL '%s'.\n";
+#endif
+
+const char err403title[] = "Forbidden";
+#ifndef EXPLICIT_ERROR_PAGES
+const char err403form[] = "You do not have permission to get URL '%s' from this server.\n";
+#endif
+
+const char err404title[] = "Not Found";
+const char err404form[] = "The requested URL '%s' was not found on this server.\n";
+
+const char httpd_err408title[] = "Request Timeout";
+const char httpd_err408form[] = "No request appeared within a reasonable time period.\n";
+
+const char err500title[] = "Internal Error";
+const char err500form[] = "There was an unusual problem serving the requested URL '%s'.\n";
+
+const char err501title[] = "Not Implemented";
+const char err501form[] = "The requested method '%s' is not implemented by this server.\n";
+
+const char httpd_err503title[] = "Service Temporarily Overloaded";
+const char httpd_err503form[] = "The requested URL '%s' is temporarily overloaded. Please try again later.\n";
+
+/* HTML strings */
+
+const char html_crlf[] = "\r\n";
+const char html_html[] = "<HTML>\r\n";
+const char html_endhtml[] = "</HTML>\r\n";
+const char html_hdtitle[] = "<HEAD><TITLE>";
+const char html_titlehd[] = "</TITLE></HEAD>\r\n";
+const char html_body[] = "<BODY BGCOLOR=\"#99cc99\" TEXT=\"#000000\" LINK=\"#2020ff\" VLINK=\"#4040cc\">\r\n";
+const char html_endbody[] = "</BODY>\r\n";
+const char html_hdr2[] = "<H2>";
+const char html_endhdr2[] = "</H2>";
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int hexit(char nibble)
+{
+ if (nibble >= '0' && nibble <= '9')
+ {
+ return nibble - '0';
+ }
+ else if (nibble >= 'a' && nibble <= 'f')
+ {
+ return nibble - 'a' + 10;
+ }
+ else if (nibble >= 'A' && nibble <= 'F')
+ {
+ return nibble - 'A' + 10;
+ }
+ return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* Copies and decodes a string. It's ok for from and to to be the same string. */
+
+void httpd_strdecode(char *to, char *from)
+{
+ for (; *from != '\0'; ++to, ++from)
+ {
+ if (from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
+ {
+ *to = hexit(from[1]) * 16 + hexit(from[2]);
+ from += 2;
+ }
+ else
+ {
+ *to = *from;
+ }
+ }
+ *to = '\0';
+}
+
+/* Copies and encodes a string. */
+
+#ifdef CONFIG_THTTPD_GENERATE_INDICES
+static void httpd_strencode(char *to, int tosize, char *from)
+{
+ int tolen;
+
+ for (tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from)
+ {
+ if (isalnum(*from) || strchr("/_.-~", *from) != NULL)
+ {
+ *to = *from;
+ ++to;
+ ++tolen;
+ }
+ else
+ {
+ (void)sprintf(to, "%%%02x", (int)*from & 0xff);
+ to += 3;
+ tolen += 3;
+ }
+ }
+ *to = '\0';
+}
+#endif /* CONFIG_THTTPD_GENERATE_INDICES */
+#endif /* CONFIG_THTTPD */
diff --git a/apps/netutils/thttpd/thttpd_strings.h b/apps/netutils/thttpd/thttpd_strings.h new file mode 100755 index 000000000..5bbaf7948 --- /dev/null +++ b/apps/netutils/thttpd/thttpd_strings.h @@ -0,0 +1,123 @@ +/****************************************************************************
+ * netutils/thttpd/thttpd_strings.h
+ * HTTP strings
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in the original THTTPD package:
+ *
+ * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __NETUTILS_THTTPD_THTTPD_STRINGS_H
+#define __NETUTILS_THTTPD_THTTPD_STRINGS_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "config.h"
+
+#ifdef CONFIG_THTTPD
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* This is the 'root' of the Filesystem as seen by the HTTP client */
+
+extern const char httpd_root[];
+
+/* HTPP status */
+
+extern const char ok200title[];
+extern const char ok206title[];
+
+extern const char err302title[];
+extern const char err302form[];
+
+extern const char err304title[];
+
+extern const char httpd_err400title[];
+extern const char httpd_err400form[];
+
+#ifdef CONFIG_THTTPD_AUTH_FILE
+extern const char err401title[];
+extern const char err401form[];
+#endif
+
+extern const char err403title[];
+#ifndef EXPLICIT_ERROR_PAGES
+extern const char err403form[];
+#endif
+
+extern const char err404title[];
+extern const char err404form[];
+
+extern const char httpd_err408title[];
+extern const char httpd_err408form[];
+
+extern const char err500title[];
+extern const char err500form[];
+
+extern const char err501title[];
+extern const char err501form[];
+
+extern const char httpd_err503title[];
+extern const char httpd_err503form[];
+
+/* HTML strings */
+
+extern const char html_crlf[];
+extern const char html_html[];
+extern const char html_endhtml[];
+extern const char html_hdtitle[];
+extern const char html_titlehd[];
+extern const char html_body[];
+extern const char html_endbody[];
+extern const char html_hdr2[];
+extern const char html_endhdr2[];
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* Copies and decodes a string. It's ok for from and to to be the same string. */
+
+extern void httpd_strdecode(char *to, char *from);
+
+/* Copies and encodes a string. */
+
+#ifdef CONFIG_THTTPD_GENERATE_INDICES
+extern void httpd_strencode(char *to, int tosize, char *from);
+#endif
+
+#endif /* CONFIG_THTTPD */
+#endif /* __NETUTILS_THTTPD_THTTPD_STRINGS_H */
diff --git a/apps/netutils/thttpd/timers.c b/apps/netutils/thttpd/timers.c new file mode 100644 index 000000000..8edd7b21b --- /dev/null +++ b/apps/netutils/thttpd/timers.c @@ -0,0 +1,365 @@ +/**************************************************************************** + * netutils/thttpd/timers.c + * Simple Timer Routines + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995,1998,2000 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/time.h> + +#include <stdlib.h> +#include <stdio.h> +#include <debug.h> + +#include "thttpd_alloc.h" +#include "timers.h" + +/**************************************************************************** + * Pre-Processor Definitons + ****************************************************************************/ + +#define HASH_SIZE 67 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static Timer *timers[HASH_SIZE]; +static Timer *free_timers; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +ClientData JunkClientData; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static unsigned int hash(Timer *tmr) +{ + /* We can hash on the trigger time, even though it can change over the + * life of a timer via the periodic bit. + * This is because both of those guys call l_resort(), which * recomputes + * the hash and moves the timer to the appropriate list. + */ + + return ((unsigned int)tmr->time.tv_sec ^ + (unsigned int)tmr->time.tv_usec) % HASH_SIZE; +} + +static void l_add(Timer *tmr) +{ + int h = tmr->hash; + register Timer *tmr2; + register Timer *tmr2prev; + + tmr2 = timers[h]; + if (tmr2 == NULL) + { + /* The list is empty. */ + timers[h] = tmr; + tmr->prev = tmr->next = NULL; + } + else + { + if (tmr->time.tv_sec < tmr2->time.tv_sec || + (tmr->time.tv_sec == tmr2->time.tv_sec && + tmr->time.tv_usec <= tmr2->time.tv_usec)) + { + /* The new timer goes at the head of the list. */ + + timers[h] = tmr; + tmr->prev = NULL; + tmr->next = tmr2; + tmr2->prev = tmr; + } + else + { + /* Walk the list to find the insertion point. */ + + for (tmr2prev = tmr2, tmr2 = tmr2->next; tmr2 != NULL; + tmr2prev = tmr2, tmr2 = tmr2->next) + { + if (tmr->time.tv_sec < tmr2->time.tv_sec || + (tmr->time.tv_sec == tmr2->time.tv_sec && + tmr->time.tv_usec <= tmr2->time.tv_usec)) + { + /* Found it. */ + tmr2prev->next = tmr; + tmr->prev = tmr2prev; + tmr->next = tmr2; + tmr2->prev = tmr; + return; + } + } + + /* Oops, got to the end of the list. Add to tail. */ + + tmr2prev->next = tmr; + tmr->prev = tmr2prev; + tmr->next = NULL; + } + } +} + +static void l_remove(Timer *tmr) +{ + int h = tmr->hash; + + if (tmr->prev == NULL) + { + timers[h] = tmr->next; + } + else + { + tmr->prev->next = tmr->next; + } + + if (tmr->next != NULL) + { + tmr->next->prev = tmr->prev; + } +} + +static void l_resort(Timer *tmr) +{ + /* Remove the timer from its old list. */ + + l_remove(tmr); + + /* Recompute the hash. */ + + tmr->hash = hash(tmr); + + /* And add it back in to its new list, sorted correctly. */ + + l_add(tmr); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void tmr_init(void) +{ + int h; + + for (h = 0; h < HASH_SIZE; ++h) + { + timers[h] = NULL; + } + + free_timers = NULL; +} + +Timer *tmr_create(struct timeval *now, TimerProc *timer_proc, + ClientData client_data, long msecs, int periodic) +{ + Timer *tmr; + + if (free_timers != NULL) + { + tmr = free_timers; + free_timers = tmr->next; + } + else + { + tmr = (Timer*)httpd_malloc(sizeof(Timer)); + if (!tmr) + { + return NULL; + } + } + + tmr->timer_proc = timer_proc; + tmr->client_data = client_data; + tmr->msecs = msecs; + tmr->periodic = periodic; + + if (now != NULL) + { + tmr->time = *now; + } + else + { + (void)gettimeofday(&tmr->time, NULL); + } + + tmr->time.tv_sec += msecs / 1000L; + tmr->time.tv_usec += (msecs % 1000L) * 1000L; + if (tmr->time.tv_usec >= 1000000L) + { + tmr->time.tv_sec += tmr->time.tv_usec / 1000000L; + tmr->time.tv_usec %= 1000000L; + } + tmr->hash = hash(tmr); + + /* Add the new timer to the proper active list. */ + + l_add(tmr); + return tmr; +} + +long tmr_mstimeout(struct timeval *now) +{ + int h; + int gotone; + long msecs, m; + register Timer *tmr; + + gotone = 0; + msecs = 0; + + /* Since the lists are sorted, we only need to look at the * first timer on + * each one. + */ + + for (h = 0; h < HASH_SIZE; ++h) + { + tmr = timers[h]; + if (tmr != NULL) + { + m = (tmr->time.tv_sec - now->tv_sec) * 1000L + + (tmr->time.tv_usec - now->tv_usec) / 1000L; + if (!gotone) + { + msecs = m; + gotone = 1; + } + else if (m < msecs) + { + msecs = m; + } + } + } + + if (!gotone) + { + return INFTIM; + } + + if (msecs <= 0) + { + msecs = 0; + } + + return msecs; +} + +void tmr_run(struct timeval *now) +{ + int h; + Timer *tmr; + Timer *next; + + for (h = 0; h < HASH_SIZE; ++h) + { + for (tmr = timers[h]; tmr != NULL; tmr = next) + { + next = tmr->next; + + /* Since the lists are sorted, as soon as we find a timer * that isn'tmr + * ready yet, we can go on to the next list + */ + + if (tmr->time.tv_sec > now->tv_sec || + (tmr->time.tv_sec == now->tv_sec && tmr->time.tv_usec > now->tv_usec)) + { + break; + } + + (tmr->timer_proc)(tmr->client_data, now); + if (tmr->periodic) + { + /* Reschedule. */ + + tmr->time.tv_sec += tmr->msecs / 1000L; + tmr->time.tv_usec += (tmr->msecs % 1000L) * 1000L; + if (tmr->time.tv_usec >= 1000000L) + { + tmr->time.tv_sec += tmr->time.tv_usec / 1000000L; + tmr->time.tv_usec %= 1000000L; + } + l_resort(tmr); + } + else + { + tmr_cancel(tmr); + } + } + } +} + +void tmr_cancel(Timer *tmr) +{ + /* Remove it from its active list. */ + + l_remove(tmr); + + /* And put it on the free list. */ + + tmr->next = free_timers; + free_timers = tmr; + tmr->prev = NULL; +} + +void tmr_cleanup(void) +{ + Timer *tmr; + + while (free_timers != NULL) + { + tmr = free_timers; + free_timers = tmr->next; + httpd_free((void*)tmr); + } +} + +void tmr_destroy(void) +{ + int h; + + for (h = 0; h < HASH_SIZE; ++h) + { + while (timers[h] != NULL) + { + tmr_cancel(timers[h]); + } + } + tmr_cleanup(); +} diff --git a/apps/netutils/thttpd/timers.h b/apps/netutils/thttpd/timers.h new file mode 100644 index 000000000..2d28d3558 --- /dev/null +++ b/apps/netutils/thttpd/timers.h @@ -0,0 +1,136 @@ +/**************************************************************************** + * netutils/thttpd/timers.h + * Header file for THTTPD timers package + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in THTTPD: + * + * Copyright © 1995,1998,1999,2000 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NETUTILS_THTTPD_TIMERS_H +#define __NETUTILS_THTTPD_TIMERS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <time.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef INFTIM +# define INFTIM -1 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* ClientData is a random value that tags along with a timer. The client + * can use it for whatever, and it gets passed to the callback when the + * timer triggers. + */ + +typedef union +{ + void *p; + int i; + long l; +} ClientData; + +/* The TimerProc gets called when the timer expires. It gets passed + * the ClientData associated with the timer, and a timeval in case + * it wants to schedule another timer. + */ + +typedef void TimerProc(ClientData client_data, struct timeval *nowP); + +/* The Timer struct. */ + +typedef struct TimerStruct +{ + TimerProc *timer_proc; + ClientData client_data; + long msecs; + int periodic; + struct timeval time; + struct TimerStruct *prev; + struct TimerStruct *next; + int hash; +} Timer; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern ClientData JunkClientData; /* For use when you don't care */ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Initialize the timer package. */ + +extern void tmr_init(void); + +/* Set up a timer, either periodic or one-shot. Returns (Timer*) 0 on errors. */ + +extern Timer *tmr_create(struct timeval *nowP, TimerProc * timer_proc, + ClientData client_data, long msecs, int periodic); + +/* Returns a timeout in milliseconds indicating how long until the next timer + * triggers. You can just put the call to this routine right in your poll(). + * Returns INFTIM (-1) if no timers are pending. + */ + +extern long tmr_mstimeout(struct timeval *nowP); + +/* Run the list of timers. Your main program needs to call this every so often. */ + +extern void tmr_run(struct timeval *nowP); + +/* Deschedule a timer. Note that non-periodic timers are automatically + * descheduled when they run, so you don't have to call this on them. + */ + +extern void tmr_cancel(Timer *timer); + +/* Clean up the timers package, freeing any unused storage. */ + +extern void tmr_cleanup(void); + +/* Cancel all timers and free storage, usually in preparation for exitting. */ + +extern void tmr_destroy(void); + +#endif /* __NETUTILS_THTTPD_TIMERS_H */ + diff --git a/apps/netutils/uiplib/Makefile b/apps/netutils/uiplib/Makefile new file mode 100644 index 000000000..52b5fe669 --- /dev/null +++ b/apps/netutils/uiplib/Makefile @@ -0,0 +1,106 @@ +############################################################################ +# apps/netutils/uiplib/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# UIP Library + +ASRCS = +CSRCS = uiplib.c uip_sethostaddr.c uip_gethostaddr.c uip_setdraddr.c \ + uip_setnetmask.c uip_parsehttpurl.c uip_server.c + +# No MAC address support for SLIP (Ethernet only) + +ifneq ($(CONFIG_NET_SLIP),y) +CSRCS += uip_setmacaddr.c uip_getmacaddr.c +endif + +# IGMP support + +ifeq ($(CONFIG_NET_IGMP),y) +CSRCS += uip_ipmsfilter.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/uiplib/uip_gethostaddr.c b/apps/netutils/uiplib/uip_gethostaddr.c new file mode 100644 index 000000000..0de639d6c --- /dev/null +++ b/apps/netutils/uiplib/uip_gethostaddr.c @@ -0,0 +1,106 @@ +/**************************************************************************** + * netutils/uiplib/uip_gethostaddr.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 + +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <string.h> +#include <errno.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uip_gethostaddr + * + * Description: + * Get the network driver IP address + * + * Parameters: + * ifname The name of the interface to use + * ipaddr The location to return the IP address + * + * Return: + * 0 on sucess; -1 on failure + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +int uip_gethostaddr(const char *ifname, struct in6_addr *addr) +#else +int uip_gethostaddr(const char *ifname, struct in_addr *addr) +#endif +{ + int ret = ERROR; + if (ifname && addr) + { + int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0); + if (sockfd >= 0) + { + struct ifreq req; + strncpy(req.ifr_name, ifname, IFNAMSIZ); + ret = ioctl(sockfd, SIOCGIFADDR, (unsigned long)&req); + if (!ret) + { +#ifdef CONFIG_NET_IPv6 +#error "req.ifr_addr.s_addr not big enough for IPv6 address" + memcpy(addr, &req.ifr_addr, sizeof(struct in6_addr)); +#else + memcpy(addr, &req.ifr_addr, sizeof(struct in_addr)); +#endif + } + } + } + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS */ diff --git a/apps/netutils/uiplib/uip_getmacaddr.c b/apps/netutils/uiplib/uip_getmacaddr.c new file mode 100644 index 000000000..c99bc7a7d --- /dev/null +++ b/apps/netutils/uiplib/uip_getmacaddr.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * netutils/uiplib/uip_getmacaddr.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 + +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uip_getmacaddr + * + * Description: + * Get the network driver IP address + * + * Parameters: + * ifname The name of the interface to use + * macaddr The location to return the MAC address + * + * Return: + * 0 on sucess; -1 on failure + * + ****************************************************************************/ + +int uip_getmacaddr(const char *ifname, uint8_t *macaddr) +{ + int ret = ERROR; + if (ifname && macaddr) + { + /* Get a socket (only so that we get access to the INET subsystem) */ + + int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0); + if (sockfd >= 0) + { + struct ifreq req; + memset (&req, 0, sizeof(struct ifreq)); + + /* Put the driver name into the request */ + + strncpy(req.ifr_name, ifname, IFNAMSIZ); + + /* Perform the ioctl to get the MAC address */ + + ret = ioctl(sockfd, SIOCGIFHWADDR, (unsigned long)&req); + if (!ret) + { + /* Return the MAC address */ + + memcpy(macaddr, &req.ifr_hwaddr.sa_data, IFHWADDRLEN); + } + } + } + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS */ diff --git a/apps/netutils/uiplib/uip_ipmsfilter.c b/apps/netutils/uiplib/uip_ipmsfilter.c new file mode 100755 index 000000000..ccae4a680 --- /dev/null +++ b/apps/netutils/uiplib/uip_ipmsfilter.c @@ -0,0 +1,116 @@ +/**************************************************************************** + * netutils/uiplib/uip_setmultiaddr.c + * + * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <debug.h> + +#include <netinet/in.h> +#include <sys/sockio.h> + +#include <apps/netutils/uiplib.h> +#include <apps/netutils/ipmsfilter.h> + +#ifdef CONFIG_NET_IGMP + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ipmsfilter + * + * Description: + * Add or remove an IP address from a multicast filter set. + * + * Parameters: + * ifname The name of the interface to use, size must less than IMSFNAMSIZ + * multiaddr Multicast group address to add/remove (network byte order) + * fmode MCAST_INCLUDE: Add multicast address + * MCAST_EXCLUDE: Remove multicast address + * + * Return: + * 0 on sucess; Negated errno on failure + * + ****************************************************************************/ + +int ipmsfilter(FAR const char *ifname, FAR const struct in_addr *multiaddr, + uint32_t fmode) +{ + int ret = ERROR; + + nvdbg("ifname: %s muliaddr: %08x fmode: %ld\n", ifname, *multiaddr, fmode); + if (ifname && multiaddr) + { + /* Get a socket (only so that we get access to the INET subsystem) */ + + int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0); + if (sockfd >= 0) + { + struct ip_msfilter imsf; + + /* Put the driver name into the request */ + + strncpy(imsf.imsf_name, ifname, IMSFNAMSIZ); + + /* Put the new address into the request */ + + imsf.imsf_multiaddr.s_addr = multiaddr->s_addr; + + /* Perforom the ioctl to set the MAC address */ + + imsf.imsf_fmode = fmode; + ret = ioctl(sockfd, SIOCSIPMSFILTER, (unsigned long)&imsf); + close(sockfd); + } + } + return ret; +} + +#endif /* CONFIG_NET_IGM */ diff --git a/apps/netutils/uiplib/uip_parsehttpurl.c b/apps/netutils/uiplib/uip_parsehttpurl.c new file mode 100644 index 000000000..bda5502b7 --- /dev/null +++ b/apps/netutils/uiplib/uip_parsehttpurl.c @@ -0,0 +1,149 @@ +/**************************************************************************** + * netutils/uiplib/uip_parsehttpurl.c + * + * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +/**************************************************************************** + * Included Files + *****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Private Data + *****************************************************************************/ + +const char g_http[] = "http://"; +#define HTTPLEN 7 + +/**************************************************************************** + * Public Functions + *****************************************************************************/ + +/**************************************************************************** + * Name: uip_parsehttpurl + ****************************************************************************/ + +int uip_parsehttpurl(const char *url, uint16_t *port, + char *hostname, int hostlen, + char *filename, int namelen) +{ + const char *src = url; + char *dest; + int bytesleft; + int ret = OK; + + /* A valid HTTP URL must begin with http:// if it does not, we will assume + * that it is a file name only, but still return an error. wget() depends + * on this strange behavior. + */ + + if (strncmp(src, g_http, HTTPLEN) != 0) + { + ret = -EINVAL; + } + else + { + /* Skip over the http:// */ + + src += HTTPLEN; + + /* Concatenate the hostname following http:// and up to the termnator */ + + dest = hostname; + bytesleft = hostlen; + while (*src != '\0' && *src != '/' && *src != ' ' && *src != ':') + { + /* Make sure that there is space for another character in the hostname. + * (reserving space for the null terminator) + */ + + if (bytesleft > 1) + { + *dest++ = *src++; + bytesleft--; + } + else + { + ret = -E2BIG; + } + } + *dest = '\0'; + + /* Check if the hostname is following by a port number */ + + if (*src == ':') + { + uint16_t accum = 0; + src++; /* Skip over the colon */ + + while (*src >= '0' && *src <= '9') + { + accum = 10*accum + *src - '0'; + src++; + } + *port = accum; + } + } + + /* The rest of the line is the file name */ + + if (*src == '\0' || *src == ' ') + { + ret = -ENOENT; + } + + /* Make sure the file name starts with exactly one '/' */ + + dest = filename; + bytesleft = namelen; + while (*src == '/') + { + src++; + } + *dest++ = '/'; + bytesleft--; + + /* The copy the rest of the file name to the user buffer */ + + strncpy(dest, src, namelen); + filename[namelen-1] = '\0'; + return ret; +} + diff --git a/apps/netutils/uiplib/uip_server.c b/apps/netutils/uiplib/uip_server.c new file mode 100644 index 000000000..f58f063de --- /dev/null +++ b/apps/netutils/uiplib/uip_server.c @@ -0,0 +1,184 @@ +/**************************************************************************** + * netutils/uiplib/uip_server.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> +#include <errno.h> +#include <debug.h> +#include <netinet/in.h> + +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uip_server + * + * Description: + * Implement basic server logic + * + * Parameters: + * portno The port to listen on (in network byte order) + * handler The entrypoint of the task to spawn when a new connection is + * accepted. + * stacksize The stack size needed by the spawned task + * + * Return: + * Does not return unless an error occurs. + * + ****************************************************************************/ + +void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize) +{ + struct sockaddr_in myaddr; +#ifdef CONFIG_NET_HAVE_SOLINGER + struct linger ling; +#endif + pthread_t child; + pthread_attr_t attr; + socklen_t addrlen; + int listensd; + int acceptsd; +#ifdef CONFIG_NET_HAVE_REUSEADDR + int optval; +#endif + + /* Create a new TCP socket to use to listen for connections */ + + listensd = socket(PF_INET, SOCK_STREAM, 0); + if (listensd < 0) + { + ndbg("socket failure: %d\n", errno); + return; + } + + /* Set socket to reuse address */ + +#ifdef CONFIG_NET_HAVE_REUSEADDR + optval = 1; + if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0) + { + ndbg("setsockopt SO_REUSEADDR failure: %d\n", errno); + goto errout_with_socket; + } +#endif + + /* Bind the socket to a local address */ + + myaddr.sin_family = AF_INET; + myaddr.sin_port = portno; + myaddr.sin_addr.s_addr = INADDR_ANY; + + if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0) + { + ndbg("bind failure: %d\n", errno); + goto errout_with_socket; + } + + /* Listen for connections on the bound TCP socket */ + + if (listen(listensd, 5) < 0) + { + ndbg("listen failure %d\n", errno); + goto errout_with_socket; + } + + /* Begin accepting connections */ + + nvdbg("Accepting connections on port %d\n", ntohs(portno)); + for (;;) + { + addrlen = sizeof(struct sockaddr_in); + acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen); + if (acceptsd < 0) + { + ndbg("accept failure: %d\n", errno); + break;; + } + nvdbg("Connection accepted -- spawning sd=%d\n", acceptsd); + + /* Configure to "linger" until all data is sent when the socket is closed */ + +#ifdef CONFIG_NET_HAVE_SOLINGER + ling.l_onoff = 1; + ling.l_linger = 30; /* timeout is seconds */ + if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0) + { + close(acceptsd); + ndbg("setsockopt SO_LINGER failure: %d\n", errno); + break;; + } +#endif + + /* Create a thread to handle the connection. The socket descriptor is + * provided in as the single argument to the new thread. + */ + + (void)pthread_attr_init(&attr); + (void)pthread_attr_setstacksize(&attr, stacksize); + + if (pthread_create(&child, &attr, handler, (void*)acceptsd) != 0) + { + close(acceptsd); + ndbg("create_create failed\n"); + break; + } + + /* We don't care when/how the child thread exits so detach from it now + * in order to avoid memory leaks. + */ + + (void)pthread_detach(child); + } + +errout_with_socket: + close(listensd); +} diff --git a/apps/netutils/uiplib/uip_setdraddr.c b/apps/netutils/uiplib/uip_setdraddr.c new file mode 100644 index 000000000..79eac5b97 --- /dev/null +++ b/apps/netutils/uiplib/uip_setdraddr.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * netutils/uiplib/uip_setdraddr.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 + +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uip_setdraddr + * + * Description: + * Set the default router IP address + * + * Parameters: + * ifname The name of the interface to use + * ipaddr The address to set + * + * Return: + * 0 on sucess; -1 on failure + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +int uip_setdraddr(const char *ifname, const struct in6_addr *addr) +#else +int uip_setdraddr(const char *ifname, const struct in_addr *addr) +#endif +{ + int ret = ERROR; + if (ifname && addr) + { + int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0); + if (sockfd >= 0) + { + struct ifreq req; +#ifdef CONFIG_NET_IPv6 + struct sockaddr_in6 *inaddr; +#else + struct sockaddr_in *inaddr; +#endif + /* Add the device name to the request */ + + strncpy(req.ifr_name, ifname, IFNAMSIZ); + + /* Add the INET address to the request */ + +#ifdef CONFIG_NET_IPv6 +#error "req.ifr_addr.s_addr not big enough for IPv6 address" + inaddr = (struct sockaddr_in6 *)&req.ifr_addr; + inaddr->sin_family = AF_INET6; + inaddr->sin_port = 0; + memcpy(&inaddr->sin6_addr, addr, sizeof(struct in6_addr)); +#else + inaddr = (struct sockaddr_in *)&req.ifr_addr; + inaddr->sin_family = AF_INET; + inaddr->sin_port = 0; + memcpy(&inaddr->sin_addr, addr, sizeof(struct in_addr)); +#endif + ret = ioctl(sockfd, SIOCSIFDSTADDR, (unsigned long)&req); + close(sockfd); + } + } + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS */ diff --git a/apps/netutils/uiplib/uip_sethostaddr.c b/apps/netutils/uiplib/uip_sethostaddr.c new file mode 100644 index 000000000..ccc7526b9 --- /dev/null +++ b/apps/netutils/uiplib/uip_sethostaddr.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * netutils/uiplib/uip_sethostaddr.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 + +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uip_sethostaddr + * + * Description: + * Set the network driver IP address + * + * Parameters: + * ifname The name of the interface to use + * ipaddr The address to set + * + * Return: + * 0 on sucess; -1 on failure + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +int uip_sethostaddr(const char *ifname, const struct in6_addr *addr) +#else +int uip_sethostaddr(const char *ifname, const struct in_addr *addr) +#endif +{ + int ret = ERROR; + if (ifname && addr) + { + int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0); + if (sockfd >= 0) + { + struct ifreq req; +#ifdef CONFIG_NET_IPv6 + struct sockaddr_in6 *inaddr; +#else + struct sockaddr_in *inaddr; +#endif + /* Add the device name to the request */ + + strncpy(req.ifr_name, ifname, IFNAMSIZ); + + /* Add the INET address to the request */ + +#ifdef CONFIG_NET_IPv6 +#error "req.ifr_addr.s_addr not big enough for IPv6 address" + inaddr = (struct sockaddr_in6 *)&req.ifr_addr; + inaddr->sin_family = AF_INET6; + inaddr->sin_port = 0; + memcpy(&inaddr->sin6_addr, addr, sizeof(struct in6_addr)); +#else + inaddr = (struct sockaddr_in *)&req.ifr_addr; + inaddr->sin_family = AF_INET; + inaddr->sin_port = 0; + memcpy(&inaddr->sin_addr, addr, sizeof(struct in_addr)); +#endif + ret = ioctl(sockfd, SIOCSIFADDR, (unsigned long)&req); + close(sockfd); + } + } + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS */ diff --git a/apps/netutils/uiplib/uip_setmacaddr.c b/apps/netutils/uiplib/uip_setmacaddr.c new file mode 100644 index 000000000..28188b7f8 --- /dev/null +++ b/apps/netutils/uiplib/uip_setmacaddr.c @@ -0,0 +1,114 @@ +/**************************************************************************** + * netutils/uiplib/uip_setmacaddr.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 + +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +# define AF_INETX AF_INET6 +#else +# define AF_INETX AF_INET +#endif + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uip_setmacaddr + * + * Description: + * Set the network driver MAC address + * + * Parameters: + * ifname The name of the interface to use + * macaddr MAC address to set, size must be IFHWADDRLEN + * + * Return: + * 0 on sucess; -1 on failure + * + ****************************************************************************/ + +int uip_setmacaddr(const char *ifname, const uint8_t *macaddr) +{ + int ret = ERROR; + if (ifname && macaddr) + { + /* Get a socket (only so that we get access to the INET subsystem) */ + + int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0); + if (sockfd >= 0) + { + struct ifreq req; + + /* Put the driver name into the request */ + + strncpy(req.ifr_name, ifname, IFNAMSIZ); + + /* Put the new MAC address into the request */ + + req.ifr_hwaddr.sa_family = AF_INETX; + memcpy(&req.ifr_hwaddr.sa_data, macaddr, IFHWADDRLEN); + + /* Perforom the ioctl to set the MAC address */ + + ret = ioctl(sockfd, SIOCSIFHWADDR, (unsigned long)&req); + close(sockfd); + } + } + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS */ diff --git a/apps/netutils/uiplib/uip_setnetmask.c b/apps/netutils/uiplib/uip_setnetmask.c new file mode 100644 index 000000000..2cdc38474 --- /dev/null +++ b/apps/netutils/uiplib/uip_setnetmask.c @@ -0,0 +1,116 @@ +/**************************************************************************** + * netutils/uiplib/uip_setnetmask.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 + +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: uip_setnetmask + * + * Description: + * Set the netmask + * + * Parameters: + * ifname The name of the interface to use + * ipaddr The address to set + * + * Return: + * 0 on sucess; -1 on failure + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +int uip_setnetmask(const char *ifname, const struct in6_addr *addr) +#else +int uip_setnetmask(const char *ifname, const struct in_addr *addr) +#endif +{ + int ret = ERROR; + if (ifname && addr) + { + int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0); + if (sockfd >= 0) + { + struct ifreq req; +#ifdef CONFIG_NET_IPv6 + struct sockaddr_in6 *inaddr; +#else + struct sockaddr_in *inaddr; +#endif + /* Add the device name to the request */ + + strncpy(req.ifr_name, ifname, IFNAMSIZ); + + /* Add the INET address to the request */ + +#ifdef CONFIG_NET_IPv6 +#error "req.ifr_addr.s_addr not big enough for IPv6 address" + inaddr = (struct sockaddr_in6 *)&req.ifr_addr; + inaddr->sin_family = AF_INET6; + inaddr->sin_port = 0; + memcpy(&inaddr->sin6_addr, addr, sizeof(struct in6_addr)); +#else + inaddr = (struct sockaddr_in *)&req.ifr_addr; + inaddr->sin_family = AF_INET; + inaddr->sin_port = 0; + memcpy(&inaddr->sin_addr, addr, sizeof(struct in_addr)); +#endif + ret = ioctl(sockfd, SIOCSIFNETMASK, (unsigned long)&req); + close(sockfd); + } + } + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS */ diff --git a/apps/netutils/uiplib/uiplib.c b/apps/netutils/uiplib/uiplib.c new file mode 100644 index 000000000..99f716f5c --- /dev/null +++ b/apps/netutils/uiplib/uiplib.c @@ -0,0 +1,95 @@ +/**************************************************************************** + * netutils/uiplib/uiplib.c + * Various uIP library functions. + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based on uIP which also has a BSD style license: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2004, Adam Dunkels and the Swedish Institute of + * Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdint.h> +#include <stdbool.h> + +#include <net/uip/uip.h> +#include <apps/netutils/uiplib.h> + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +bool uiplib_ipaddrconv(const char *addrstr, uint8_t *ipaddr) +{ + unsigned char tmp; + char c; + unsigned char i; + unsigned char j; + + tmp = 0; + + for (i = 0; i < 4; ++i) + { + j = 0; + do + { + c = *addrstr; + ++j; + if (j > 4) + { + return false; + } + if (c == '.' || c == 0) + { + *ipaddr = tmp; + ++ipaddr; + tmp = 0; + } + else if(c >= '0' && c <= '9') + { + tmp = (tmp * 10) + (c - '0'); + } + else + { + return false; + } + ++addrstr; + } + while(c != '.' && c != 0); + } + return true; +} diff --git a/apps/netutils/webclient/Makefile b/apps/netutils/webclient/Makefile new file mode 100644 index 000000000..e6616e8c8 --- /dev/null +++ b/apps/netutils/webclient/Makefile @@ -0,0 +1,97 @@ +############################################################################ +# apps/netutils/webclient/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Web client library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_TCP),y) +CSRCS = webclient.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/webclient/webclient.c b/apps/netutils/webclient/webclient.c new file mode 100644 index 000000000..e52f592f5 --- /dev/null +++ b/apps/netutils/webclient/webclient.c @@ -0,0 +1,583 @@ +/**************************************************************************** + * netutils/webclient/webclient.c + * Implementation of the HTTP client. + * + * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based on uIP which also has a BSD style license: + * + * Author: Adam Dunkels <adam@dunkels.com> + * Copyright (c) 2002, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* This example shows a HTTP client that is able to download web pages + * and files from web servers. It requires a number of callback + * functions to be implemented by the module that utilizes the code: + * webclient_datahandler(). + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifndef CONFIG_WEBCLIENT_HOST +# include <nuttx/config.h> +# include <nuttx/compiler.h> +# include <debug.h> +#endif + +#include <sys/socket.h> +#include <stdint.h> +#include <stdbool.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#ifdef CONFIG_HAVE_GETHOSTBYNAME +# include <netdb.h> +#else +# include <apps/netutils/resolv.h> +#endif + +#include <arpa/inet.h> +#include <netinet/in.h> +#include <apps/netutils/uiplib.h> +#include <apps/netutils/webclient.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define WEBCLIENT_TIMEOUT 100 + +#define WEBCLIENT_STATE_STATUSLINE 0 +#define WEBCLIENT_STATE_HEADERS 1 +#define WEBCLIENT_STATE_DATA 2 +#define WEBCLIENT_STATE_CLOSE 3 + +#define HTTPSTATUS_NONE 0 +#define HTTPSTATUS_OK 1 +#define HTTPSTATUS_MOVED 2 +#define HTTPSTATUS_ERROR 3 + +#define ISO_nl 0x0a +#define ISO_cr 0x0d +#define ISO_space 0x20 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct wget_s +{ + /* Internal status */ + + uint8_t state; + uint8_t httpstatus; + + uint16_t port; /* The port number to use in the connection */ + + /* These describe the just-received buffer of data */ + + FAR char *buffer; /* user-provided buffer */ + int buflen; /* Length of the user provided buffer */ + int offset; /* Offset to the beginning of interesting data */ + int datend; /* Offset+1 to the last valid byte of data in the buffer */ + + /* Buffer HTTP header data and parse line at a time */ + + char line[CONFIG_WEBCLIENT_MAXHTTPLINE]; + int ndx; + +#ifdef CONFIG_WEBCLIENT_GETMIMETYPE + char mimetype[CONFIG_WEBCLIENT_MAXMIMESIZE]; +#endif + char hostname[CONFIG_WEBCLIENT_MAXHOSTNAME]; + char filename[CONFIG_WEBCLIENT_MAXFILENAME]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_http10[] = "HTTP/1.0"; +static const char g_http11[] = "HTTP/1.1"; +#ifdef CONFIG_WEBCLIENT_GETMIMETYPE +static const char g_httpcontenttype[] = "content-type: "; +#endif +static const char g_httphost[] = "host: "; +static const char g_httplocation[] = "location: "; +static const char g_httpget[] = "GET "; + +static const char g_httpuseragentfields[] = + "Connection: close\r\n" + "User-Agent: NuttX/0.4.x (; http://www.nuttx.org/)\r\n\r\n"; + +static const char g_http200[] = "200 "; +static const char g_http301[] = "301 "; +static const char g_http302[] = "302 "; + +static const char g_httpcrnl[] = "\r\n"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: wget_strcpy + ****************************************************************************/ + +static char *wget_strcpy(char *dest, const char *src) +{ + int len = strlen(src); + memcpy(dest, src, len); + dest[len] = '\0'; + return dest + len; +} + +/**************************************************************************** + * Name: wget_resolvehost + ****************************************************************************/ + +static inline int wget_resolvehost(const char *hostname, in_addr_t *ipaddr) +{ +#ifdef CONFIG_HAVE_GETHOSTBYNAME + + struct hostent *he; + + nvdbg("Getting address of %s\n", hostname); + he = gethostbyname(hostname); + if (!he) + { + ndbg("gethostbyname failed: %d\n", h_errno); + return ERROR; + } + + nvdbg("Using IP address %04x%04x\n", (uint16_t)he->h_addr[1], (uint16_t)he->h_addr[0]); + memcpy(ipaddr, he->h_addr, sizeof(in_addr_t)); + return OK; + +#else + +# ifdef CONFIG_NET_IPv6 + struct sockaddr_in6 addr; +# else + struct sockaddr_in addr; +# endif + + /* First check if the host is an IP address. */ + + if (!uiplib_ipaddrconv(hostname, (uint8_t*)ipaddr)) + { + /* 'host' does not point to a valid address string. Try to resolve + * the host name to an IP address. + */ + + if (resolv_query(hostname, &addr) < 0) + { + /* Needs to set the errno here */ + + return ERROR; + } + + /* Save the host address -- Needs fixed for IPv6 */ + + *ipaddr = addr.sin_addr.s_addr; + } + return OK; + +#endif +} + +/**************************************************************************** + * Name: wget_parsestatus + ****************************************************************************/ + +static inline int wget_parsestatus(struct wget_s *ws) +{ + int offset; + int ndx; + char *dest; + + offset = ws->offset; + ndx = ws->ndx; + + while (offset < ws->datend) + { + ws->line[ndx] = ws->buffer[offset]; + if (ws->line[ndx] == ISO_nl) + { + ws->line[ndx] = '\0'; + if ((strncmp(ws->line, g_http10, strlen(g_http10)) == 0) || + (strncmp(ws->line, g_http11, strlen(g_http11)) == 0)) + { + dest = &(ws->line[9]); + ws->httpstatus = HTTPSTATUS_NONE; + + /* Check for 200 OK */ + + if (strncmp(dest, g_http200, strlen(g_http200)) == 0) + { + ws->httpstatus = HTTPSTATUS_OK; + } + + /* Check for 301 Moved permanently or 302 Found. Location: header line + * will contain the new location. + */ + + else if (strncmp(dest, g_http301, strlen(g_http301)) == 0 || + strncmp(dest, g_http302, strlen(g_http302)) == 0) + { + + ws->httpstatus = HTTPSTATUS_MOVED; + } + } + else + { + return - ECONNABORTED; + } + + /* We're done parsing the status line, so start parsing the HTTP headers. */ + + ws->state = WEBCLIENT_STATE_HEADERS; + break; + } + else + { + offset++; + ndx++; + } + } + + ws->offset = offset; + ws->ndx = ndx; + return OK; +} + +/**************************************************************************** + * Name: wget_parsestatus + ****************************************************************************/ + +static inline int wget_parseheaders(struct wget_s *ws) +{ + int offset; + int ndx; + + offset = ws->offset; + ndx = ws->ndx; + + while (offset < ws->datend) + { + ws->line[ndx] = ws->buffer[offset]; + if (ws->line[ndx] == ISO_nl) + { + /* We have an entire HTTP header line in s.line, so + * we parse it. + */ + + if (ndx > 0) /* Should always be true */ + { + if (ws->line[0] == ISO_cr) + { + /* This was the last header line (i.e., and empty "\r\n"), so + * we are done with the headers and proceed with the actual + * data. + */ + + ws->state = WEBCLIENT_STATE_DATA; + goto exit; + } + + /* Truncate the trailing \r\n */ + + ws->line[ndx-1] = '\0'; + + /* Check for specific HTTP header fields. */ + +#ifdef CONFIG_WEBCLIENT_GETMIMETYPE + if (strncasecmp(ws->line, g_httpcontenttype, strlen(g_httpcontenttype)) == 0) + { + /* Found Content-type field. */ + + char *dest = strchr(ws->line, ';'); + if (dest != NULL) + { + *dest = 0; + } + strncpy(ws->mimetype, ws->line + strlen(g_httpcontenttype), sizeof(ws->mimetype)); + } + else +#endif + if (strncasecmp(ws->line, g_httplocation, strlen(g_httplocation)) == 0) + { + /* Parse the new HTTP host and filename from the URL. Note that + * the return value is ignored. In the event of failure, we + * retain the current location. + */ + + (void)uip_parsehttpurl(ws->line + strlen(g_httplocation), &ws->port, + ws->hostname, CONFIG_WEBCLIENT_MAXHOSTNAME, + ws->filename, CONFIG_WEBCLIENT_MAXFILENAME); + nvdbg("New hostname='%s' filename='%s'\n", ws->hostname, ws->filename); + } + } + + /* We're done parsing this line, so we reset the index to the start + * of the next line. + */ + + ndx = 0; + } + else + { + ndx++; + } + offset++; + } + +exit: + ws->offset = offset; + ws->ndx = ndx; + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: wget + * + * Description: + * Obtain the requested file from an HTTP server using the GET method. + * + * Note: If the function is passed a host name, it must already be in + * the resolver cache in order for the function to connect to the web + * server. It is therefore up to the calling module to implement the + * resolver calls and the signal handler used for reporting a resolv + * query answer. + * + * Input Parameters + * url - A pointer to a string containing either the full URL to + * the file to get (e.g., http://www.nutt.org/index.html, or + * http://192.168.23.1:80/index.html). + * buffer - A user provided buffer to receive the file data (also + * used for the outgoing GET request + * buflen - The size of the user provided buffer + * callback - As data is obtained from the host, this function is + * to dispose of each block of file data as it is received. + * + * Returned Value: + * 0: if the GET operation completed successfully; + * -1: On a failure with errno set appropriately + * + ****************************************************************************/ + +int wget(FAR const char *url, FAR char *buffer, int buflen, + wget_callback_t callback, FAR void *arg) +{ + struct sockaddr_in server; + struct wget_s ws; + bool redirected; + char *dest; + int sockfd; + int len; + int ret = OK; + + /* Initialize the state structure */ + + memset(&ws, 0, sizeof(struct wget_s)); + ws.buffer = buffer; + ws.buflen = buflen; + ws.port = 80; + + /* Parse the hostname (with optional port number) and filename from the URL */ + + ret = uip_parsehttpurl(url, &ws.port, + ws.hostname, CONFIG_WEBCLIENT_MAXHOSTNAME, + ws.filename, CONFIG_WEBCLIENT_MAXFILENAME); + if (ret != 0) + { + ndbg("Malformed HTTP URL: %s\n", url); + set_errno(-ret); + return ERROR; + } + nvdbg("hostname='%s' filename='%s'\n", ws.hostname, ws.filename); + + /* The following sequence may repeat indefinitely if we are redirected */ + + do + { + /* Re-initialize portions of the state structure that could have + * been left from the previous time through the loop and should not + * persist with the new connection. + */ + + ws.httpstatus = HTTPSTATUS_NONE; + ws.offset = 0; + ws.datend = 0; + ws.ndx = 0; + + /* Create a socket */ + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + { + /* socket failed. It will set the errno appropriately */ + + ndbg("socket failed: %d\n", errno); + return ERROR; + } + + /* Get the server adddress from the host name */ + + server.sin_family = AF_INET; + server.sin_port = htons(ws.port); + ret = wget_resolvehost(ws.hostname, &server.sin_addr.s_addr); + if (ret < 0) + { + /* Could not resolve host (or malformed IP address) */ + + ndbg("Failed to resolve hostname\n"); + ret = -EHOSTUNREACH; + goto errout_with_errno; + } + + /* Connect to server. First we have to set some fields in the + * 'server' address structure. The system will assign me an arbitrary + * local port that is not in use. + */ + + ret = connect(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)); + if (ret < 0) + { + ndbg("connect failed: %d\n", errno); + goto errout; + } + + /* Send the GET request */ + + dest = ws.buffer; + dest = wget_strcpy(dest, g_httpget); + dest = wget_strcpy(dest, ws.filename); + *dest++ = ISO_space; + dest = wget_strcpy(dest, g_http10); + dest = wget_strcpy(dest, g_httpcrnl); + dest = wget_strcpy(dest, g_httphost); + dest = wget_strcpy(dest, ws.hostname); + dest = wget_strcpy(dest, g_httpcrnl); + dest = wget_strcpy(dest, g_httpuseragentfields); + len = dest - buffer; + + ret = send(sockfd, buffer, len, 0); + if (ret < 0) + { + ndbg("send failed: %d\n", errno); + goto errout; + } + + /* Now loop to get the file sent in response to the GET. This + * loop continues until either we read the end of file (nbytes == 0) + * or until we detect that we have been redirected. + */ + + ws.state = WEBCLIENT_STATE_STATUSLINE; + redirected = false; + for(;;) + { + ws.datend = recv(sockfd, ws.buffer, ws.buflen, 0); + if (ws.datend < 0) + { + ndbg("recv failed: %d\n", errno); + ret = ws.datend; + goto errout_with_errno; + } + else if (ret == 0) + { + close(sockfd); + break; + } + + /* Handle initial parsing of the status line */ + + ws.offset = 0; + if (ws.state == WEBCLIENT_STATE_STATUSLINE) + { + ret = wget_parsestatus(&ws); + if (ret < 0) + { + goto errout_with_errno; + } + } + + /* Parse the HTTP data */ + + if (ws.state == WEBCLIENT_STATE_HEADERS) + { + ret = wget_parseheaders(&ws); + if (ret < 0) + { + goto errout_with_errno; + } + } + + /* Dispose of the data payload */ + + if (ws.state == WEBCLIENT_STATE_DATA) + { + if (ws.httpstatus != HTTPSTATUS_MOVED) + { + /* Let the client decide what to do with the received file */ + + callback(&ws.buffer, ws.offset, ws.datend, &buflen, arg); + } + else + { + redirected = true; + close(sockfd); + break; + } + } + } + } + while (redirected); + return OK; + +errout_with_errno: + set_errno(-ret); +errout: + close(sockfd); + return ERROR; +} diff --git a/apps/netutils/webserver/Makefile b/apps/netutils/webserver/Makefile new file mode 100644 index 000000000..a1422a249 --- /dev/null +++ b/apps/netutils/webserver/Makefile @@ -0,0 +1,97 @@ +############################################################################ +# apps/netutils/webserver/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Web server library + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_TCP),y) +CSRCS = httpd.c httpd_fs.c httpd_cgi.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/webserver/httpd.c b/apps/netutils/webserver/httpd.c new file mode 100644 index 000000000..9322b58dc --- /dev/null +++ b/apps/netutils/webserver/httpd.c @@ -0,0 +1,498 @@ +/**************************************************************************** + * netutils/webserver/httpd.c + * httpd Web server + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * This is a leverage of similar logic from uIP: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2004, Adam Dunkels. + * All rights reserved. + * + * The uIP web server is a very simplistic implementation of an HTTP + * server. It can serve web pages and files from a read-only ROM + * filesystem, and provides a very small scripting language. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <errno.h> +#include <debug.h> + +#include <net/uip/uip.h> +#include <apps/netutils/uiplib.h> +#include <apps/netutils/httpd.h> + +#include "httpd.h" +#include "httpd_cgi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ISO_nl 0x0a +#define ISO_space 0x20 +#define ISO_bang 0x21 +#define ISO_percent 0x25 +#define ISO_period 0x2e +#define ISO_slash 0x2f +#define ISO_colon 0x3a + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_httpcontenttypebinary[] = "Content-type: application/octet-stream\r\n\r\n"; +static const char g_httpcontenttypecss[] = "Content-type: text/css\r\n\r\n"; +static const char g_httpcontenttypegif[] = "Content-type: image/gif\r\n\r\n"; +static const char g_httpcontenttypehtml[] = "Content-type: text/html\r\n\r\n"; +static const char g_httpcontenttypejpg[] = "Content-type: image/jpeg\r\n\r\n"; +static const char g_httpcontenttypeplain[] = "Content-type: text/plain\r\n\r\n"; +static const char g_httpcontenttypepng[] = "Content-type: image/png\r\n\r\n"; + +static const char g_httpextensionhtml[] = ".html"; +static const char g_httpextensionshtml[] = ".shtml"; +static const char g_httpextensioncss[] = ".css"; +static const char g_httpextensionpng[] = ".png"; +static const char g_httpextensiongif[] = ".gif"; +static const char g_httpextensionjpg[] = ".jpg"; + +static const char g_http404path[] = "/404.html"; +static const char g_httpindexpath[] = "/index.html"; + +static const char g_httpcmdget[] = "GET "; + +static const char g_httpheader200[] = + "HTTP/1.0 200 OK\r\n" + "Server: uIP/1.0 http://www.sics.se/~adam/uip/\r\n" + "Connection: close\r\n"; + +static const char g_httpheader404[] = + "HTTP/1.0 404 Not found\r\n" + "Server: uIP/1.0 http://www.sics.se/~adam/uip/\r\n" + "Connection: close\r\n"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_NETUTILS_HTTPD_DUMPBUFFER +static void httpd_dumpbuffer(FAR const char *msg, FAR const char *buffer, unsigned int nbytes) +{ + /* CONFIG_DEBUG, CONFIG_DEBUG_VERBOSE, and CONFIG_DEBUG_NET have to be + * defined or the following does nothing. + */ + + nvdbgdumpbuffer(msg, (FAR const uint8_t*)buffer, nbytes); +} +#else +# define httpd_dumpbuffer(msg,buffer,nbytes) +#endif + +#ifdef CONFIG_NETUTILS_HTTPD_DUMPPSTATE +static void httpd_dumppstate(struct httpd_state *pstate, const char *msg) +{ +#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_NET) + nvdbg("[%d] pstate(%p): [%s]\n", pstate->ht_sockfd, pstate, msg); + nvdbg(" filename: [%s]\n", pstate->ht_filename); + nvdbg(" htfile len: %d\n", pstate->ht_file.len); + nvdbg(" sockfd: %d\n", pstate->ht_sockfd); + nvdbg(" scriptptr: %p\n", pstate->ht_scriptptr); + nvdbg(" scriptlen: %d\n", pstate->ht_scriptlen); + nvdbg(" sndlen: %d\n", pstate->ht_sndlen); +#endif +} +#else +# define httpd_dumppstate(pstate, msg) +#endif + +static void next_scriptstate(struct httpd_state *pstate) +{ + char *p; + p = strchr(pstate->ht_scriptptr, ISO_nl) + 1; + pstate->ht_scriptlen -= (unsigned short)(p - pstate->ht_scriptptr); + pstate->ht_scriptptr = p; +} + +static int handle_script(struct httpd_state *pstate) +{ + int len; + char *ptr; + + while (pstate->ht_file.len > 0) + { + /* Check if we should start executing a script */ + + if (*pstate->ht_file.data == ISO_percent && *(pstate->ht_file.data + 1) == ISO_bang) + { + pstate->ht_scriptptr = pstate->ht_file.data + 3; + pstate->ht_scriptlen = pstate->ht_file.len - 3; + if (*(pstate->ht_scriptptr - 1) == ISO_colon) + { + httpd_fs_open(pstate->ht_scriptptr + 1, &pstate->ht_file); + send(pstate->ht_sockfd, pstate->ht_file.data, pstate->ht_file.len, 0); + } + else + { + httpd_cgi(pstate->ht_scriptptr)(pstate, pstate->ht_scriptptr); + } + next_scriptstate(pstate); + + /* The script is over, so we reset the pointers and continue + * sending the rest of the file + */ + + pstate->ht_file.data = pstate->ht_scriptptr; + pstate->ht_file.len = pstate->ht_scriptlen; + } + else + { + /* See if we find the start of script marker in the block of HTML + * to be sent + */ + + if (pstate->ht_file.len > HTTPD_IOBUFFER_SIZE) + { + len = HTTPD_IOBUFFER_SIZE; + } + else + { + len = pstate->ht_file.len; + } + + if (*pstate->ht_file.data == ISO_percent) + { + ptr = strchr(pstate->ht_file.data + 1, ISO_percent); + } + else + { + ptr = strchr(pstate->ht_file.data, ISO_percent); + } + + if (ptr != NULL && ptr != pstate->ht_file.data) + { + len = (int)(ptr - pstate->ht_file.data); + if (len >= HTTPD_IOBUFFER_SIZE) + { + len = HTTPD_IOBUFFER_SIZE; + } + } + send(pstate->ht_sockfd, pstate->ht_file.data, len, 0); + pstate->ht_file.data += len; + pstate->ht_file.len -= len; + } + } + return OK; +} + +static int httpd_addchunk(struct httpd_state *pstate, const char *buffer, int len) +{ + int newlen; + int chunklen; + int ret; + + do + { + /* Determine the size of the next chunk so that it fits into the buffer */ + + newlen = pstate->ht_sndlen + len; + if (newlen > HTTPD_IOBUFFER_SIZE) + { + newlen = HTTPD_IOBUFFER_SIZE; + chunklen = HTTPD_IOBUFFER_SIZE - pstate->ht_sndlen; + } + else + { + chunklen = len; + } + nvdbg("[%d] sndlen=%d len=%d newlen=%d chunklen=%d\n", + pstate->ht_sockfd, pstate->ht_sndlen, len, newlen, chunklen); + + /* Copy that chunk into the send buffer */ + + memcpy(&pstate->ht_buffer[pstate->ht_sndlen], buffer, chunklen); + + if (newlen >= HTTPD_IOBUFFER_SIZE) + { + /* The buffer is full.. Send what we have and reset to send again */ + + httpd_dumpbuffer("Outgoing buffer", pstate->ht_buffer, newlen); + ret = send(pstate->ht_sockfd, pstate->ht_buffer, newlen, 0); + if (ret < 0) + { + return ret; + } + + newlen = 0; + } + + pstate->ht_sndlen = newlen; + len -= chunklen; + buffer += chunklen; + } + while (len > 0); + return OK; +} + +static int send_headers(struct httpd_state *pstate, const char *statushdr, int len) +{ + char *ptr; + int ret; + + ret = httpd_addchunk(pstate, statushdr, len); + if (ret < 0) + { + return ret; + } + + ptr = strrchr(pstate->ht_filename, ISO_period); + if (ptr == NULL) + { + ret = httpd_addchunk(pstate, g_httpcontenttypebinary, strlen(g_httpcontenttypebinary)); + } + else if (strncmp(g_httpextensionhtml, ptr, strlen(g_httpextensionhtml)) == 0 || + strncmp(g_httpextensionshtml, ptr, strlen(g_httpextensionshtml)) == 0) + { + ret = httpd_addchunk(pstate, g_httpcontenttypehtml, strlen(g_httpcontenttypehtml)); + } + else if (strncmp(g_httpextensioncss, ptr, strlen(g_httpextensioncss)) == 0) + { + ret = httpd_addchunk(pstate, g_httpcontenttypecss, strlen(g_httpcontenttypecss)); + } + else if (strncmp(g_httpextensionpng, ptr, strlen(g_httpextensionpng)) == 0) + { + ret = httpd_addchunk(pstate, g_httpcontenttypepng, strlen(g_httpcontenttypepng)); + } + else if (strncmp(g_httpextensiongif, ptr, strlen(g_httpextensiongif)) == 0) + { + ret = httpd_addchunk(pstate, g_httpcontenttypegif, strlen(g_httpcontenttypegif)); + } + else if (strncmp(g_httpextensionjpg, ptr, strlen(g_httpextensionjpg)) == 0) + { + ret = httpd_addchunk(pstate, g_httpcontenttypejpg, strlen(g_httpcontenttypejpg)); + } + else + { + ret = httpd_addchunk(pstate, g_httpcontenttypeplain, strlen(g_httpcontenttypeplain)); + } + + return ret; +} + +static int httpd_sendfile(struct httpd_state *pstate) +{ + char *ptr; + int ret = ERROR; + + pstate->ht_sndlen = 0; + + nvdbg("[%d] sending file '%s'\n", pstate->ht_sockfd, pstate->ht_filename); + if (!httpd_fs_open(pstate->ht_filename, &pstate->ht_file)) + { + ndbg("[%d] '%s' not found\n", pstate->ht_sockfd, pstate->ht_filename); + memcpy(pstate->ht_filename, g_http404path, strlen(g_http404path)); + httpd_fs_open(g_http404path, &pstate->ht_file); + if (send_headers(pstate, g_httpheader404, strlen(g_httpheader404)) == OK) + { + ret = httpd_addchunk(pstate, pstate->ht_file.data, pstate->ht_file.len); + } + } + else + { + if (send_headers(pstate, g_httpheader200, strlen(g_httpheader200)) == OK) + { + ptr = strchr(pstate->ht_filename, ISO_period); + if (ptr != NULL && + strncmp(ptr, g_httpextensionshtml, strlen(g_httpextensionshtml)) == 0) + { + ret = handle_script(pstate); + } + else + { + ret = httpd_addchunk(pstate, pstate->ht_file.data, pstate->ht_file.len); + } + } + } + + /* Send anything remaining in the buffer */ + + if (ret == OK && pstate->ht_sndlen > 0) + { + httpd_dumpbuffer("Outgoing buffer", pstate->ht_buffer, pstate->ht_sndlen); + if (send(pstate->ht_sockfd, pstate->ht_buffer, pstate->ht_sndlen, 0) < 0) + { + ret = ERROR; + } + } + + return ret; +} + +static inline int httpd_cmd(struct httpd_state *pstate) +{ + ssize_t recvlen; + int i; + + /* Get the next HTTP command. We will handle only GET */ + + recvlen = recv(pstate->ht_sockfd, pstate->ht_buffer, HTTPD_IOBUFFER_SIZE, 0); + if (recvlen < 0) + { + ndbg("[%d] recv failed: %d\n", pstate->ht_sockfd, errno); + return ERROR; + } + httpd_dumpbuffer("Incoming buffer", pstate->ht_buffer, recvlen); + + /* We will handle only GET */ + + if (strncmp(pstate->ht_buffer, g_httpcmdget, strlen(g_httpcmdget)) != 0) + { + ndbg("[%d] Unsupported command\n", pstate->ht_sockfd); + return ERROR; + } + + /* Get the name of the file to provide */ + + if (pstate->ht_buffer[4] != ISO_slash) + { + ndbg("[%d] Missing path\n", pstate->ht_sockfd); + return ERROR; + } + else if (pstate->ht_buffer[5] == ISO_space) + { + strncpy(pstate->ht_filename, g_httpindexpath, strlen(g_httpindexpath)); + } + else + { + for (i = 0; + i < (HTTPD_MAX_FILENAME-1) && pstate->ht_buffer[i+4] != ISO_space; + i++) + { + pstate->ht_filename[i] = pstate->ht_buffer[i+4]; + } + pstate->ht_filename[i]='\0'; + } + nvdbg("[%d] Filename: %s\n", pstate->ht_sockfd, pstate->ht_filename); + + /* Then send the file */ + + return httpd_sendfile(pstate); +} + +/**************************************************************************** + * Name: httpd_handler + * + * Description: + * Each time a new connection to port 80 is made, a new thread is created + * that begins at this entry point. There should be exactly one argument + * and it should be the socket descriptor (+1). + * + ****************************************************************************/ + +static void *httpd_handler(void *arg) +{ + struct httpd_state *pstate = (struct httpd_state *)malloc(sizeof(struct httpd_state)); + int sockfd = (int)arg; + int ret = ERROR; + + nvdbg("[%d] Started\n", sockfd); + + /* Verify that the state structure was successfully allocated */ + + if (pstate) + { + /* Re-initialize the thread state structure */ + + memset(pstate, 0, sizeof(struct httpd_state)); + pstate->ht_sockfd = sockfd; + + /* Then handle the next httpd command */ + + ret = httpd_cmd(pstate); + + /* End of command processing -- Clean up and exit */ + + free(pstate); + } + + /* Exit the task */ + + nvdbg("[%d] Exitting\n", sockfd); + close(sockfd); + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/**************************************************************************** + * Name: httpd_listen + * + * Description: + * This is the main processing thread for the webserver. It never returns + * unless an error occurs + * + ****************************************************************************/ + +int httpd_listen(void) +{ + /* Execute httpd_handler on each connection to port 80 */ + + uip_server(HTONS(80), httpd_handler, CONFIG_NETUTILS_HTTPDSTACKSIZE); + + /* uip_server only returns on errors */ + + return ERROR; +} + +/**************************************************************************** + * Name: httpd_init + * + * Description: + * This function initializes the web server and should be called at system + * boot-up. + * + ****************************************************************************/ + +void httpd_init(void) +{ +} diff --git a/apps/netutils/webserver/httpd.h b/apps/netutils/webserver/httpd.h new file mode 100644 index 000000000..52073765c --- /dev/null +++ b/apps/netutils/webserver/httpd.h @@ -0,0 +1,118 @@ +/**************************************************************************** + * netutils/webserver/httpd.h + * + * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based on uIP which also has a BSD style license: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2001-2005, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef _NETUTILS_WEBSERVER_HTTPD_H +#define _NETUTILS_WEBSERVER_HTTPD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdint.h> +#include <net/uip/uip.h> +#include <net/uip/uipopt.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* As threads are created to handle each request, a stack must be allocated + * for the thread. Use a default if the user provided no stacksize. + */ + +#ifndef CONFIG_NETUTILS_HTTPDSTACKSIZE +# define CONFIG_NETUTILS_HTTPDSTACKSIZE 4096 +#endif + +#undef CONFIG_NETUTILS_HTTPDFSSTATS +#define CONFIG_NETUTILS_HTTPDFSSTATS 1 + +#ifndef CONFIG_NET_STATISTICS +# undef CONFIG_NETUTILS_HTTPDNETSTATS +#endif + +/* For efficiency reasons, the size of the IO buffer should be a multiple + * of the TCP MSS value. Also, the current design requires that the IO + * buffer be sufficiently large to contain the entire GET request. + */ + +#define HTTPD_IOBUFFER_SIZE (3*UIP_TCP_MSS) + +/* this is the maximum size of a file path */ + +#define HTTPD_MAX_FILENAME 20 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct httpd_fs_file +{ + char *data; + int len; +}; + +struct httpd_state +{ + char ht_buffer[HTTPD_IOBUFFER_SIZE]; /* recv()/send() buffer */ + char ht_filename[HTTPD_MAX_FILENAME]; /* filename from GET command */ + struct httpd_fs_file ht_file; /* Fake file data to send */ + int ht_sockfd; /* The socket descriptor from accept() */ + char *ht_scriptptr; + uint16_t ht_scriptlen; + uint16_t ht_sndlen; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_NETUTILS_HTTPDFSSTATS +#if CONFIG_NETUTILS_HTTPDFSSTATS == 1 +extern uint16_t httpd_fs_count(char *name); +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ + +/* file must be allocated by caller and will be filled in by the function. */ + +int httpd_fs_open(const char *name, struct httpd_fs_file *file); +void httpd_fs_init(void); + +#endif /* _NETUTILS_WEBSERVER_HTTPD_H */ diff --git a/apps/netutils/webserver/httpd_cgi.c b/apps/netutils/webserver/httpd_cgi.c new file mode 100644 index 000000000..967ef9b9c --- /dev/null +++ b/apps/netutils/webserver/httpd_cgi.c @@ -0,0 +1,170 @@ +/**************************************************************************** + * httpd_cgi.c + * Web server script interface + * Author: Adam Dunkels <adam@sics.se> + * + * Copyright (c) 2001-2006, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> + +#include <nuttx/compiler.h> + +#include <net/uip/uip.h> +#include <apps/netutils/httpd.h> + +#include "httpd_cgi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void nullfunction(struct httpd_state *pstate, char *ptr); +#ifdef CONFIG_NETUTILS_HTTPDNETSTATS +static void net_stats(struct httpd_state *pstate, char *ptr); +#endif + +#ifdef CONFIG_NETUTILS_HTTPDFILESTATS +static void file_stats(struct httpd_state *pstate, char *ptr); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_NETUTILS_HTTPDFILESTATS +HTTPD_CGI_CALL(file, "file-stats", file_stats); +#endif +#ifdef CONFIG_NETUTILS_HTTPDNETSTATS +HTTPD_CGI_CALL(net, "net-stats", net_stats); +#endif + +static const struct httpd_cgi_call *calls[] = +{ +#ifdef CONFIG_NETUTILS_HTTPDFILESTATS + &file, +#endif +#ifdef CONFIG_NETUTILS_HTTPDNETSTATS + &net, +#endif + NULL +}; + +static const char closed[] = /* "CLOSED",*/ + {0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0}; +static const char syn_rcvd[] = /* "SYN-RCVD",*/ + {0x53, 0x59, 0x4e, 0x2d, 0x52, 0x43, 0x56, 0x44, 0}; +static const char syn_sent[] = /* "SYN-SENT",*/ + {0x53, 0x59, 0x4e, 0x2d, 0x53, 0x45, 0x4e, 0x54, 0}; +static const char established[] = /* "ESTABLISHED",*/ + {0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0}; +static const char fin_wait_1[] = /* "FIN-WAIT-1",*/ + {0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, 0x54, 0x2d, 0x31, 0}; +static const char fin_wait_2[] = /* "FIN-WAIT-2",*/ + {0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, 0x54, 0x2d, 0x32, 0}; +static const char closing[] = /* "CLOSING",*/ + {0x43, 0x4c, 0x4f, 0x53, 0x49, 0x4e, 0x47, 0}; +static const char time_wait[] = /* "TIME-WAIT,"*/ + {0x54, 0x49, 0x4d, 0x45, 0x2d, 0x57, 0x41, 0x49, 0x54, 0}; +static const char last_ack[] = /* "LAST-ACK"*/ + {0x4c, 0x41, 0x53, 0x54, 0x2d, 0x41, 0x43, 0x4b, 0}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nullfunction + ****************************************************************************/ + +static void nullfunction(struct httpd_state *pstate, char *ptr) +{ +} + +/**************************************************************************** + * Name: net_stats + ****************************************************************************/ + +#ifdef CONFIG_NETUTILS_HTTPDNETSTATS +static void net_stats(struct httpd_state *pstate, char *ptr) +{ + char buffer[16]; + int i; + + for (i = 0; i < sizeof(uip_stat) / sizeof(uip_stats_t); i++) + { + snprintf(buffer, 16, "%5u\n", ((uip_stats_t *)&uip_stat)[i]); + send(pstate->ht_sockfd, buffer, strlen(buffer), 0); + } +} +#endif + +/**************************************************************************** + * Name: file_stats + ****************************************************************************/ + +#ifdef CONFIG_NETUTILS_HTTPDFILESTATS +static void file_stats(struct httpd_state *pstate, char *ptr) +{ + char buffer[16]; + char *pcount = strchr(ptr, ' ') + 1; + snprintf(buffer, 16, "%5u", httpd_fs_count(pcount)); + (void)send(pstate->ht_sockfd, buffer, strlen(buffer), 0); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +httpd_cgifunction httpd_cgi(char *name) +{ + const struct httpd_cgi_call **f; + + /* Find the matching name in the table, return the function. */ + + for(f = calls; *f != NULL; ++f) + { + if(strncmp((*f)->name, name, strlen((*f)->name)) == 0) + { + return (*f)->function; + } + } + return nullfunction; +} diff --git a/apps/netutils/webserver/httpd_cgi.h b/apps/netutils/webserver/httpd_cgi.h new file mode 100644 index 000000000..9547bca33 --- /dev/null +++ b/apps/netutils/webserver/httpd_cgi.h @@ -0,0 +1,69 @@ +/* httpd_cgi.h + * Web server script interface header file + * Author: Adam Dunkels <adam@sics.se> + * + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HTTPD_CGI_H__ +#define __HTTPD_CGI_H__ + +#include <apps/netutils/httpd.h> + +#include "httpd.h" + +typedef void (*httpd_cgifunction)(struct httpd_state *, char *); + +httpd_cgifunction httpd_cgi(char *name); + +struct httpd_cgi_call +{ + const char *name; + httpd_cgifunction function; +}; + +/** + * \brief HTTPD CGI function declaration + * \param name The C variable name of the function + * \param str The string name of the function, used in the script file + * \param function A pointer to the function that implements it + * + * This macro is used for declaring a HTTPD CGI + * function. This function is then added to the list of + * HTTPD CGI functions with the httpd_cgi_add() function. + * + * \hideinitializer + */ +#define HTTPD_CGI_CALL(name, str, function) \ +static void function(struct httpd_state *, char *); \ +static const struct httpd_cgi_call name = {str, function} + +void httpd_cgi_init(void); +#endif /* __HTTPD_CGI_H__ */ + +/** @} */ diff --git a/apps/netutils/webserver/httpd_fs.c b/apps/netutils/webserver/httpd_fs.c new file mode 100644 index 000000000..731f19498 --- /dev/null +++ b/apps/netutils/webserver/httpd_fs.c @@ -0,0 +1,155 @@ +/**************************************************************************** + * netutils/webserver/httpd_fs.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based on uIP which also has a BSD style license: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Header Files + ****************************************************************************/ + +#include <stdint.h> + +#include <apps/netutils/httpd.h> + +#include "httpd.h" +#include "httpd_fsdata.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#include "httpd_fsdata.c" + +#if CONFIG_NETUTILS_HTTPDFSSTATS +static uint16_t count[HTTPD_FS_NUMFILES]; +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint8_t httpd_fs_strcmp(const char *str1, const char *str2) +{ + int i; + + i = 0; + for (;;) + { + if (str2[i] == 0 || str1[i] == '\r' || str1[i] == '\n') + { + return 0; + } + + if (str1[i] != str2[i]) + { + return 1; + } + + i++; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int httpd_fs_open(const char *name, struct httpd_fs_file *file) +{ +#if CONFIG_NETUTILS_HTTPDFSSTATS + uint16_t i = 0; +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ + struct httpd_fsdata_file_noconst *f; + + for(f = (struct httpd_fsdata_file_noconst *)HTTPD_FS_ROOT; + f != NULL; + f = (struct httpd_fsdata_file_noconst *)f->next) + { + if (httpd_fs_strcmp(name, f->name) == 0) + { + file->data = f->data; + file->len = f->len; +#if CONFIG_NETUTILS_HTTPDFSSTATS + ++count[i]; +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ + return 1; + } +#if CONFIG_NETUTILS_HTTPDFSSTATS + ++i; +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ + } + return 0; +} + +void httpd_fs_init(void) +{ +#if CONFIG_NETUTILS_HTTPDFSSTATS + uint16_t i; + for(i = 0; i < HTTPD_FS_NUMFILES; i++) + { + count[i] = 0; + } +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ +} + +#if CONFIG_NETUTILS_HTTPDFSSTATS +uint16_t httpd_fs_count(char *name) +{ + struct httpd_fsdata_file_noconst *f; + uint16_t i; + + i = 0; + for(f = (struct httpd_fsdata_file_noconst *)HTTPD_FS_ROOT; + f != NULL; + f = (struct httpd_fsdata_file_noconst *)f->next) + { + if (httpd_fs_strcmp(name, f->name) == 0) + { + return count[i]; + } + ++i; + } + return 0; +} +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ diff --git a/apps/netutils/webserver/httpd_fsdata.c b/apps/netutils/webserver/httpd_fsdata.c new file mode 100644 index 000000000..c9cd8a20c --- /dev/null +++ b/apps/netutils/webserver/httpd_fsdata.c @@ -0,0 +1,614 @@ +static const unsigned char data_processes_shtml[] = +{ + /* /processes.shtml */ + + 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x3c, 0x68, 0x31, + 0x3e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x70, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x3c, 0x2f, 0x68, + 0x31, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0x0a, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x49, 0x44, 0x3c, 0x2f, 0x74, + 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4e, 0x61, 0x6d, 0x65, + 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, + 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x3c, 0x2f, 0x74, + 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, 0x6f, 0x6c, 0x6c, + 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x3c, 0x2f, + 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, + 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, + 0x72, 0x6f, 0x63, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3c, 0x2f, + 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x25, + 0x21, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x0a, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, 0x6f, 0x6f, + 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0 +}; + +static const unsigned char data_404_html[] = +{ + /* /404.html */ + + 0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x0a, 0x20, 0x20, 0x3c, + 0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, + 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x63, 0x65, 0x6e, + 0x74, 0x65, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3c, 0x68, 0x31, 0x3e, 0x34, 0x30, 0x34, 0x20, 0x2d, + 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, + 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x3c, 0x2f, 0x68, 0x31, 0x3e, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x68, 0x33, + 0x3e, 0x47, 0x6f, 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, + 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, + 0x61, 0x64, 0x2e, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, + 0x79, 0x3e, 0x0a, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, + 0 +}; + +static const unsigned char data_files_shtml[] = +{ + /* /files.shtml */ + + 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x3c, 0x68, 0x31, + 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x68, 0x31, + 0x3e, 0x0a, 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, + 0x0a, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x33, 0x30, 0x30, 0x22, 0x3e, + 0x0a, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, + 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, + 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0x0a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, + 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, 0x3d, + 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, + 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x31, + 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x25, 0x21, + 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, + 0x73, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0x0a, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, + 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, + 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, + 0x0a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, + 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, 0x3d, 0x22, + 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x22, + 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x31, 0x30, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x25, 0x21, 0x20, + 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, + 0x20, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, + 0x74, 0x6d, 0x6c, 0x0a, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, 0x74, 0x63, 0x70, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, + 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x20, 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, + 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, + 0x72, 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, + 0x70, 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, + 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x74, 0x63, 0x70, 0x2e, + 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x3e, 0x20, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x73, 0x74, 0x61, + 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, + 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, + 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, + 0x6d, 0x6c, 0x0a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, + 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, + 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, + 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, + 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x25, + 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, + 0x74, 0x73, 0x20, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, + 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x3e, 0x20, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 0x3e, 0x2f, 0x73, + 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x3c, 0x2f, + 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x74, + 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x0a, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, + 0x20, 0x73, 0x72, 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, + 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, + 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x0a, 0x3e, 0x20, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, + 0x0a, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x34, + 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, + 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x3c, 0x2f, + 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x74, + 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x34, 0x30, 0x34, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, + 0x73, 0x72, 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, + 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x34, 0x30, 0x34, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x3e, 0x20, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, + 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x3e, 0x2f, 0x66, 0x61, + 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x3c, 0x2f, 0x61, 0x3e, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x0a, 0x3c, 0x74, 0x64, 0x3e, + 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x20, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, + 0x70, 0x6e, 0x67, 0x0a, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, + 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, + 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, + 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x20, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, + 0x70, 0x6e, 0x67, 0x0a, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0x0a, 0x3c, 0x2f, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x3e, 0x0a, 0x3c, 0x2f, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x0a, 0x25, 0x21, 0x3a, 0x20, + 0x2f, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x0a, 0 +}; + +static const unsigned char data_footer_html[] = +{ + /* /footer.html */ + + 0x2f, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x0a, + 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0 +}; + +static const unsigned char data_header_html[] = +{ + /* /header.html */ + + 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, + 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, + 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x57, 0x33, 0x43, 0x2f, + 0x2f, 0x44, 0x54, 0x44, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, + 0x34, 0x2e, 0x30, 0x31, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x2f, 0x45, + 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x54, 0x52, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x34, + 0x2f, 0x6c, 0x6f, 0x6f, 0x73, 0x65, 0x2e, 0x64, 0x74, 0x64, + 0x22, 0x3e, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x0a, + 0x20, 0x20, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, + 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x49, 0x50, 0x20, 0x77, + 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x21, + 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x72, + 0x65, 0x6c, 0x3d, 0x22, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, + 0x68, 0x65, 0x65, 0x74, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, + 0x22, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 0x3e, 0x20, + 0x20, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, + 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, + 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, + 0x66, 0x66, 0x66, 0x65, 0x65, 0x63, 0x22, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x3d, 0x22, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x22, + 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, + 0x75, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, + 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x46, + 0x72, 0x6f, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x67, 0x65, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, + 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6f, + 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, + 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, + 0x65, 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x74, 0x63, 0x70, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, + 0x20, 0x20, 0x3c, 0x62, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x0a, 0x20, + 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3e, 0x0a, 0 +}; + +static const unsigned char data_index_html[] = +{ + /* /index.html */ + + 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, + 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, + 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x57, 0x33, 0x43, 0x2f, + 0x2f, 0x44, 0x54, 0x44, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, + 0x34, 0x2e, 0x30, 0x31, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x2f, 0x45, + 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x54, 0x52, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x34, + 0x2f, 0x6c, 0x6f, 0x6f, 0x73, 0x65, 0x2e, 0x64, 0x74, 0x64, + 0x22, 0x3e, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x0a, + 0x20, 0x20, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, + 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x49, 0x50, 0x20, 0x77, + 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x21, + 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x72, + 0x65, 0x6c, 0x3d, 0x22, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, + 0x68, 0x65, 0x65, 0x74, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, + 0x22, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 0x3e, 0x20, + 0x20, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, + 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, + 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, + 0x66, 0x66, 0x66, 0x65, 0x65, 0x63, 0x22, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x3d, 0x22, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x22, + 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, + 0x75, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, + 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x46, + 0x72, 0x6f, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x67, 0x65, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, + 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6f, + 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, + 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, + 0x65, 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x74, 0x63, 0x70, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x0a, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, + 0x20, 0x20, 0x3c, 0x62, 0x72, 0x3e, 0x0a, 0x20, 0x20, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x3c, + 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, + 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x70, + 0x3e, 0x0a, 0x20, 0x20, 0x54, 0x68, 0x65, 0x73, 0x65, 0x20, + 0x77, 0x65, 0x62, 0x20, 0x70, 0x61, 0x67, 0x65, 0x73, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x6d, 0x61, 0x6c, + 0x6c, 0x20, 0x77, 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, + 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x70, 0x20, 0x6f, 0x66, + 0x0a, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, + 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, + 0x2f, 0x75, 0x69, 0x70, 0x2f, 0x22, 0x3e, 0x75, 0x49, 0x50, + 0x20, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, + 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0x0a, 0x20, 0x20, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0x0a, + 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0a, 0x20, 0x20, 0x3c, + 0x70, 0x3e, 0x0a, 0x20, 0x20, 0x43, 0x6c, 0x69, 0x63, 0x6b, + 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, + 0x6e, 0x6b, 0x73, 0x20, 0x61, 0x62, 0x6f, 0x76, 0x65, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x77, 0x65, 0x62, 0x20, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x3c, + 0x2f, 0x70, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x62, + 0x6f, 0x64, 0x79, 0x3e, 0x0a, 0x3c, 0x2f, 0x68, 0x74, 0x6d, + 0x6c, 0x3e, 0x0a, 0 +}; + +static const unsigned char data_style_css[] = +{ + /* /style.css */ + + 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0, + 0x68, 0x31, 0x20, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0x0a, 0x20, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, + 0x31, 0x34, 0x70, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6f, + 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, + 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, + 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0x0a, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x3a, 0x62, 0x6f, 0x6c, 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x70, + 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x31, 0x30, 0x70, + 0x78, 0x3b, 0x20, 0x0a, 0x7d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, + 0x79, 0x0a, 0x7b, 0x0a, 0x0a, 0x20, 0x20, 0x62, 0x61, 0x63, + 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, 0x65, + 0x65, 0x63, 0x3b, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x3a, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x3b, 0x0a, 0x0a, + 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, + 0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, + 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, + 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0x0a, 0x7d, 0x0a, + 0x0a, 0x2e, 0x6d, 0x65, 0x6e, 0x75, 0x0a, 0x7b, 0x0a, 0x20, + 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x34, + 0x70, 0x78, 0x3b, 0x0a, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3a, 0x36, 0x30, 0x25, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x32, 0x70, + 0x78, 0x3b, 0x0a, 0x09, 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x3a, 0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, + 0x20, 0x31, 0x70, 0x78, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x61, + 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, + 0x63, 0x64, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x6c, 0x65, + 0x66, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x39, + 0x70, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, + 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, + 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, + 0x69, 0x63, 0x61, 0x3b, 0x20, 0x20, 0x0a, 0x7d, 0x0a, 0x0a, + 0x64, 0x69, 0x76, 0x2e, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6f, + 0x78, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3a, 0x20, 0x32, 0x35, 0x25, 0x3b, 0x0a, 0x20, 0x20, + 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x30, 0x3b, + 0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, + 0x6c, 0x65, 0x66, 0x74, 0x3b, 0x0a, 0x74, 0x65, 0x78, 0x74, + 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x0a, 0x7b, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x6d, + 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x34, 0x70, 0x78, + 0x3b, 0x0a, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, + 0x36, 0x30, 0x25, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x32, 0x70, 0x78, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x3a, 0x20, 0x31, 0x70, 0x78, 0x20, 0x64, 0x6f, 0x74, 0x74, + 0x65, 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, + 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x3a, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x3b, + 0x0a, 0x0a, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, + 0x69, 0x7a, 0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 0x0a, 0x20, + 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, + 0x6c, 0x79, 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, + 0x65, 0x6c, 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0x20, + 0x20, 0x0a, 0x0a, 0x7d, 0x0a, 0x0a, 0x70, 0x2e, 0x69, 0x6e, + 0x74, 0x72, 0x6f, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x6d, 0x61, + 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x6c, 0x65, 0x66, 0x74, 0x3a, + 0x32, 0x30, 0x70, 0x78, 0x3b, 0x0a, 0x20, 0x20, 0x6d, 0x61, + 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x3a, 0x32, 0x30, 0x70, 0x78, 0x3b, 0x0a, 0x0a, 0x20, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, + 0x31, 0x30, 0x70, 0x74, 0x3b, 0x0a, 0x2f, 0x2a, 0x20, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x3a, 0x62, 0x6f, 0x6c, 0x64, 0x3b, 0x20, 0x2a, 0x2f, + 0x0a, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, + 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, + 0x3b, 0x20, 0x20, 0x0a, 0x7d, 0x0a, 0x0a, 0x70, 0x2e, 0x63, + 0x6c, 0x69, 0x6e, 0x6b, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x31, + 0x32, 0x70, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6f, 0x6e, + 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x63, + 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x2c, 0x6d, 0x6f, 0x6e, + 0x6f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3b, 0x20, 0x20, 0x0a, + 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3a, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, + 0x0a, 0x7d, 0x0a, 0x0a, 0x70, 0x2e, 0x63, 0x6c, 0x69, 0x6e, + 0x6b, 0x39, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x66, 0x6f, 0x6e, + 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x39, 0x70, 0x74, + 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, + 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x63, 0x6f, 0x75, 0x72, + 0x69, 0x65, 0x72, 0x2c, 0x6d, 0x6f, 0x6e, 0x6f, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x3b, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x74, + 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0x0a, 0x7d, 0x0a, + 0x0a, 0x0a, 0x70, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6c, 0x65, 0x66, 0x74, + 0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, + 0x70, 0x2e, 0x72, 0x69, 0x67, 0x68, 0x74, 0x0a, 0x7b, 0x0a, + 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3a, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3b, 0x20, + 0x0a, 0x7d, 0x0a, 0x0a, 0 +}; + +static const unsigned char data_fade_png[] = +{ + /* /fade.png */ + + 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x00, + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, + 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0a, 0x08, 0x02, 0x00, 0x00, 0x00, 0x1c, + 0x99, 0x68, 0x59, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, + 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, + 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, + 0x4d, 0x45, 0x07, 0xd6, 0x06, 0x08, 0x14, 0x1b, 0x39, 0xaf, + 0x5b, 0xc0, 0xe3, 0x00, 0x00, 0x00, 0x1d, 0x74, 0x45, 0x58, + 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4d, 0x50, + 0xef, 0x64, 0x25, 0x6e, 0x00, 0x00, 0x00, 0x3a, 0x49, 0x44, + 0x41, 0x54, 0x08, 0xd7, 0x75, 0x8c, 0x31, 0x12, 0x00, 0x10, + 0x10, 0xc4, 0x2e, 0x37, 0x9e, 0x40, 0x65, 0xfd, 0xff, 0x83, + 0xf4, 0x0a, 0x1c, 0x8d, 0x54, 0x9b, 0xc9, 0xcc, 0x9a, 0x3d, + 0x90, 0x73, 0x71, 0x67, 0x91, 0xd4, 0x74, 0x36, 0xa9, 0x55, + 0x01, 0xf8, 0x29, 0x58, 0xc8, 0xbf, 0x48, 0xc4, 0x81, 0x74, + 0x0b, 0xa3, 0x0f, 0x7c, 0xdb, 0x04, 0xe8, 0x40, 0x05, 0xdf, + 0xa1, 0xf3, 0xfc, 0x73, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0 +}; + +static const unsigned char data_stats_shtml[] = +{ + /* /stats.shtml */ + + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x0a, 0x3c, 0x68, 0x31, + 0x3e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x3c, + 0x2f, 0x68, 0x31, 0x3e, 0x0a, 0x3c, 0x63, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x3e, 0x0a, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x33, 0x30, + 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, + 0x22, 0x30, 0x22, 0x3e, 0x0a, 0x3c, 0x74, 0x72, 0x3e, 0x3c, + 0x74, 0x64, 0x3e, 0x3c, 0x70, 0x72, 0x65, 0x3e, 0x0a, 0x49, + 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, + 0x73, 0x65, 0x6e, 0x74, 0x0a, 0x09, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x64, + 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x0a, 0x49, 0x50, 0x20, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x20, 0x20, 0x20, 0x20, + 0x49, 0x50, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x50, + 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x2c, 0x20, 0x68, + 0x69, 0x67, 0x68, 0x20, 0x62, 0x79, 0x74, 0x65, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x49, 0x50, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x2c, 0x20, 0x6c, 0x6f, 0x77, 0x20, 0x62, 0x79, 0x74, + 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x50, 0x20, 0x66, 0x72, + 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x57, 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x0a, 0x49, 0x43, 0x4d, 0x50, 0x09, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x64, + 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x54, 0x79, 0x70, 0x65, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x73, 0x0a, 0x54, 0x43, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x64, + 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x20, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, + 0x61, 0x74, 0x61, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, + 0x41, 0x43, 0x4b, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, + 0x73, 0x65, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x0a, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x4e, 0x6f, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x76, 0x61, 0x6c, 0x69, 0x61, + 0x62, 0x6c, 0x65, 0x0a, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x20, + 0x70, 0x6f, 0x72, 0x74, 0x73, 0x0a, 0x3c, 0x2f, 0x70, 0x72, + 0x65, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, + 0x3e, 0x3c, 0x70, 0x72, 0x65, 0x3e, 0x25, 0x21, 0x20, 0x6e, + 0x65, 0x74, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x0a, 0x3c, + 0x2f, 0x70, 0x72, 0x65, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x3e, 0x0a, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x3e, 0x0a, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, + 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0x0a, 0 +}; + +const struct httpd_fsdata_file file_processes_shtml[] = + {{NULL, data_processes_shtml, data_processes_shtml + 17, sizeof(data_processes_shtml) - 18}}; + +const struct httpd_fsdata_file file_404_html[] = + {{file_processes_shtml, data_404_html, data_404_html + 10, sizeof(data_404_html) - 11}}; + +const struct httpd_fsdata_file file_files_shtml[] = + {{file_404_html, data_files_shtml, data_files_shtml + 13, sizeof(data_files_shtml) - 14}}; + +const struct httpd_fsdata_file file_footer_html[] = + {{file_files_shtml, data_footer_html, data_footer_html + 13, sizeof(data_footer_html) - 14}}; + +const struct httpd_fsdata_file file_header_html[] = + {{file_footer_html, data_header_html, data_header_html + 13, sizeof(data_header_html) - 14}}; + +const struct httpd_fsdata_file file_index_html[] = + {{file_header_html, data_index_html, data_index_html + 12, sizeof(data_index_html) - 13}}; + +const struct httpd_fsdata_file file_style_css[] = + {{file_index_html, data_style_css, data_style_css + 11, sizeof(data_style_css) - 12}}; + +const struct httpd_fsdata_file file_fade_png[] = + {{file_style_css, data_fade_png, data_fade_png + 10, sizeof(data_fade_png) - 11}}; + +const struct httpd_fsdata_file file_stats_shtml[] = + {{file_fade_png, data_stats_shtml, data_stats_shtml + 13, sizeof(data_stats_shtml) - 14}}; + +#define HTTPD_FS_ROOT file_stats_shtml +#define HTTPD_FS_NUMFILES 10 diff --git a/apps/netutils/webserver/httpd_fsdata.h b/apps/netutils/webserver/httpd_fsdata.h new file mode 100644 index 000000000..d0a69affa --- /dev/null +++ b/apps/netutils/webserver/httpd_fsdata.h @@ -0,0 +1,79 @@ +/**************************************************************************** + * netutils/webserver/httpd_fsdata.h + * + * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Based on uIP which also has a BSD style license: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __HTTPD_FSDATA_H__ +#define __HTTPD_FSDATA_H__ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdint.h> +#include <net/uip/uip.h> + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct httpd_fsdata_file +{ + const struct httpd_fsdata_file *next; + FAR const uint8_t *name; + FAR const uint8_t *data; + int len; +#ifdef CONFIG_NETUTILS_HTTPDFSSTATS +#if CONFIG_NETUTILS_HTTPDFSSTATS == 1 + uint16_t count; +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ +}; + +struct httpd_fsdata_file_noconst +{ + FAR struct httpd_fsdata_file *next; + FAR char *name; + FAR char *data; + int len; +#ifdef CONFIG_NETUTILS_HTTPDFSSTATS +#if CONFIG_NETUTILS_HTTPDFSSTATS == 1 + uint16_t count; +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ +#endif /* CONFIG_NETUTILS_HTTPDFSSTATS */ +}; + +#endif /* __HTTPD_FSDATA_H__ */ diff --git a/apps/netutils/webserver/makefsdata b/apps/netutils/webserver/makefsdata new file mode 100755 index 000000000..71b6bd344 --- /dev/null +++ b/apps/netutils/webserver/makefsdata @@ -0,0 +1,75 @@ +#!/usr/bin/perl + +open(OUTPUT, "> httpd-fsdata.c"); + +chdir("httpd-fs"); + +opendir(DIR, "."); +@files = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); +closedir(DIR); + +foreach $file (@files) { + + if(-d $file && $file !~ /^\./) { + print "Processing directory $file\n"; + opendir(DIR, $file); + @newfiles = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); + closedir(DIR); + printf "Adding files @newfiles\n"; + @files = (@files, map { $_ = "$file/$_" } @newfiles); + next; + } +} + +foreach $file (@files) { + if(-f $file) { + + print "Adding file $file\n"; + + open(FILE, $file) || die "Could not open file $file\n"; + + $file =~ s-^-/-; + $fvar = $file; + $fvar =~ s-/-_-g; + $fvar =~ s-\.-_-g; + # for AVR, add PROGMEM here + print(OUTPUT "static const unsigned char data".$fvar."[] =\n"); + print(OUTPUT "{\n /* $file */\n\n "); + for($j = 0; $j < length($file); $j++) { + printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1))); + } + printf(OUTPUT "0x00,\n "); + + $i = 0; + while(read(FILE, $data, 1)) { + printf(OUTPUT "%#02x, ", unpack("C", $data)); + $i++; + if($i == 10) { + print(OUTPUT "\n"); + $i = 0; + print(OUTPUT " "); + } + } + print(OUTPUT "0x00\n};\n\n"); + close(FILE); + push(@fvars, $fvar); + push(@pfiles, $file); + } +} + +for($i = 0; $i < @fvars; $i++) { + $file = $pfiles[$i]; + $fvar = $fvars[$i]; + + if($i == 0) { + $prevfile = "NULL"; + } else { + $prevfile = "file" . $fvars[$i - 1]; + } + print(OUTPUT "const struct httpd_fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, "); + print(OUTPUT "data$fvar + ". (length($file) + 1) .", "); + print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n"); +} + +print(OUTPUT "#define HTTPD_FS_ROOT file$fvars[$i - 1]\n\n"); +print(OUTPUT "#define HTTPD_FS_NUMFILES $i\n"); diff --git a/apps/nshlib/Makefile b/apps/nshlib/Makefile new file mode 100644 index 000000000..91ffc2c5e --- /dev/null +++ b/apps/nshlib/Makefile @@ -0,0 +1,124 @@ +############################################################################ +# apps/nshlib/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# NSH Library + +ASRCS = +CSRCS = nsh_parse.c nsh_fscmds.c nsh_ddcmd.c nsh_proccmds.c nsh_mmcmds.c \ + nsh_envcmds.c nsh_dbgcmds.c + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +CSRCS += nsh_apps.c +endif + +ifeq ($(CONFIG_NSH_ROMFSETC),y) +CSRCS += nsh_romfsetc.c +endif + +ifeq ($(CONFIG_NET),y) +CSRCS += nsh_netinit.c nsh_netcmds.c +endif + +ifeq ($(CONFIG_RTC),y) +CSRCS += nsh_timcmds.c +endif + +ifeq ($(CONFIG_NSH_CONSOLE),y) +CSRCS += nsh_serial.c +endif + +ifeq ($(CONFIG_NSH_TELNET),y) +CSRCS += nsh_telnetd.c +endif + +ifneq ($(CONFIG_NSH_DISABLESCRIPT),y) +CSRCS += nsh_test.c +endif + + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . +VPATH = + +# Build targets + +all: .built +.PHONY: context .depend depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) \ + $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/nshlib/README.txt b/apps/nshlib/README.txt new file mode 100644 index 000000000..fad1ac104 --- /dev/null +++ b/apps/nshlib/README.txt @@ -0,0 +1,1049 @@ +apps/nshlib +^^^^^^^^^^^ + + This directory contains the NuttShell (NSH) library. This library can be + linked with other logic to provide a simple shell application for NuttX. + + - Console/NSH Front End + - Command Overview + - Conditional Command Execution + - Built-In Variables + - Current Working Directory + Environment Variables + - NSH Start-Up Script + - Simple Commands + - NSH Configuration Settings + Command Dependencies on Configuration Settings + NSH-Specific Configuration Settings + - Common Problems + +Console/NSH Front End +^^^^^^^^^^^^^^^^^^^^^ + + Using settings in the configuration file, NSH may be configured to + use either the serial stdin/out or a telnet connection as the console + or BOTH. When NSH is started, you will see the following welcome on + either console: + + NuttShell (NSH) + nsh> + + 'nsh>' is the NSH prompt and indicates that you may enter a command + from the console. + +Command Overview +^^^^^^^^^^^^^^^^ + + This directory contains the NuttShell (NSH). This is a simple + shell-like application. At present, NSH supports the following commands + forms: + + Simple command: <cmd> + Command with re-directed output: <cmd> > <file> + <cmd> >> <file> + Background command: <cmd> & + Re-directed background command: <cmd> > <file> & + <cmd> >> <file> & + + Where: + + <cmd> is any one of the simple commands listed later. + <file> is the full or relative path to any writable object + in the filesystem name space (file or character driver). + Such objects will be referred to simply as files throughout + this README. + + NSH executes at the mid-priority (128). Backgrounded commands can + be made to execute at higher or lower priorities using nice: + + [nice [-d <niceness>>]] <cmd> [> <file>|>> <file>] [&] + + Where <niceness> is any value between -20 and 19 where lower + (more negative values) correspond to higher priorities. The + default niceness is 10. + +Conditional Command Execution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + An if-then[-else]-fi construct is also supported in order to + support conditional execution of commands. This works from the + command line but is primarily intended for use within NSH scripts + (see the sh commnd). The syntax is as follows: + + if <cmd> + then + [sequence of <cmd>] + else + [sequence of <cmd>] + fi + +Built-In Variables +^^^^^^^^^^^^^^^^^^ + + $? - The result of the last simple command execution + +Current Working Directory +^^^^^^^^^^^^^^^^^^^^^^^^^ + + All path arguments to commands may be either an absolute path or a + path relative to the current working directory. The current working + directory is set using the 'cd' command and can be queried either + by using the 'pwd' command or by using the 'echo $PWD' command. + + Environment Variables: + ---------------------- + + PWD - The current working directory + OLDPWD - The previous working directory + +NSH Start-Up Script +^^^^^^^^^^^^^^^^^^^ + +NSH supports options to provide a start up script for NSH. In general +this capability is enabled with CONFIG_NSH_ROMFSETC, but has +several other related configuration options as described in the final +section of this README. This capability also depends on: + + - CONFIG_DISABLE_MOUNTPOINT not set + - CONFIG_NFILE_DESCRIPTORS < 4 + - CONFIG_FS_ROMFS + +Default Start-Up Behavior +------------------------- + +The implementation that is provided is intended to provide great flexibility +for the use of Start-Up files. This paragraph will discuss the general +behavior when all of the configuration options are set to the default +values. + +In this default case, enabling CONFIG_NSH_ROMFSETC will cause +NSH to behave as follows at NSH startup time: + +- NSH will create a read-only RAM disk (a ROM disk), containing a tiny + ROMFS filesystem containing the following: + + |--init.d/ + `-- rcS + + Where rcS is the NSH start-up script + +- NSH will then mount the ROMFS filesystem at /etc, resulting in: + + |--dev/ + | `-- ram0 + `--etc/ + `--init.d/ + `-- rcS + +- By default, the contents of rcS script are: + + # Create a RAMDISK and mount it at XXXRDMOUNTPOUNTXXX + + mkrd -m 1 -s 512 1024 + mkfatfs /dev/ram1 + mount -t vfat /dev/ram1 /tmp + +- NSH will execute the script at /etc/init.d/rcS at start-up (before the + first NSH prompt. After execution of the script, the root FS will look + like: + + |--dev/ + | |-- ram0 + | `-- ram1 + |--etc/ + | `--init.d/ + | `-- rcS + `--tmp/ + +Modifying the ROMFS Image +------------------------- + +The contents of the /etc directory are retained in the file +apps/nshlib/nsh_romfsimg.h (OR, if CONFIG_NSH_ARCHROMFS +is defined, include/arch/board/rcs.template). In order to modify +the start-up behavior, there are three things to study: + +1. Configuration Options. + The additional CONFIG_NSH_ROMFSETC configuration options + discussed in the final section of this README. + +2. tools/mkromfsimg.sh Script. + The script tools/mkromfsimg.sh creates nsh_romfsimg.h. + It is not automatically executed. If you want to change the + configuration settings associated with creating and mounting + the /tmp directory, then it will be necessary to re-generate + this header file using the mkromfsimg.sh script. + + The behavior of this script depends upon three things: + + - The configuration settings of the installed NuttX configuration. + - The genromfs tool (available from http://romfs.sourceforge.net). + - The file apps/nshlib/rcS.template (OR, if + CONFIG_NSH_ARCHROMFS is defined, include/arch/board/rcs.template) + +3. rcS.template. + The file apps/nshlib/rcS.template contains the general form + of the rcS file; configured values are plugged into this + template file to produce the final rcS file. + +NOTE: + + apps/nshlib/rcS.template generates the standard, default + nsh_romfsimg.h file. If CONFIG_NSH_ARCHROMFS is defined + in the NuttX configuration file, then a custom, board-specific + nsh_romfsimg.h file residing in configs/<board>/include will be + used. NOTE when the OS is configured, include/arch/board will + be linked to configs/<board>/include. + +All of the startup-behavior is contained in rcS.template. The +role of mkromfsimg.sh is to (1) apply the specific configuration +settings to rcS.template to create the final rcS, and (2) to +generate the header file nsh_romfsimg.h containg the ROMFS +file system image. + +Simple Commands +^^^^^^^^^^^^^^^ + +o [ <expression> ] +o test <expression> + + These are two alternative forms of the same command. They support + evaluation of a boolean expression which sets $?. This command + is used most frequently as the conditional command following the + 'if' in the if-then[-else]-fi construct. + + Expression Syntax: + ------------------ + + expression = simple-expression | !expression | + expression -o expression | expression -a expression + + simple-expression = unary-expression | binary-expression + + unary-expression = string-unary | file-unary + + string-unary = -n string | -z string + + file-unary = -b file | -c file | -d file | -e file | -f file | + -r file | -s file | -w file + + binary-expression = string-binary | numeric-binary + + string-binary = string = string | string == string | string != string + + numeric-binary = integer -eq integer | integer -ge integer | + integer -gt integer | integer -le integer | + integer -lt integer | integer -ne integer + +o cat <path> [<path> [<path> ...]] + + This command copies and concatentates all of the files at <path> + to the console (or to another file if the output is redirected). + +o cd [<dir-path>|-|~|..] + + Changes the current working directory (PWD). Also sets the + previous working directory environment variable (OLDPWD). + + FORMS: + ------ + + 'cd <dir-path>' sets the current working directory to <dir-path>. + 'cd -' sets the current working directory to the previous + working directory ($OLDPWD). Equivalent to 'cd $OLDPWD'. + 'cd' or 'cd ~' set the current working directory to the 'home' + directory. The 'home' directory can be configured by setting + CONFIG_LIB_HOMEDIR in the configuration file. The default + 'home' directory is '/'. + 'cd ..' sets the current working directory to the parent directory. + +o cp <source-path> <dest-path> + + Copy of the contents of the file at <source-path> to the location + in the filesystem indicated by <path-path> + +o date [-s "MMM DD HH:MM:SS YYYY"] + + Show or set the current date and time. This command is only supported + if the platform supported RTC hardware (CONFIG_RTC=y). + + Only one format is used both on display and when setting the date/time: + MMM DD HH:MM:SS YYYY. For example, + + data -s "Sep 1 11:30:00 2011" + + 24-hour time format is assumed. + +o dd if=<infile> of=<outfile> [bs=<sectsize>] [count=<sectors>] [skip=<sectors>] + + Copy blocks from <infile> to <outfile>. <nfile> or <outfile> may + be the path to a standard file, a character device, or a block device. + + Examples: + + 1. Read from character device, write to regular file. This will + create a new file of the specified size filled with zero. + + nsh> dd if=/dev/zero of=/tmp/zeros bs=64 count=16 + nsh> ls -l /tmp + /tmp: + -rw-rw-rw- 1024 ZEROS + + 2. Read from character device, write to block device. This will + fill the entire block device with zeros. + + nsh> ls -l /dev + /dev: + brw-rw-rw- 0 ram0 + crw-rw-rw- 0 zero + nsh> dd if=/dev/zero of=/dev/ram0 + + 3. Read from a block devic, write to a character device. This + will read the entire block device and dump the contents in + the bit bucket. + + nsh> ls -l /dev + /dev: + crw-rw-rw- 0 null + brw-rw-rw- 0 ram0 + nsh> dd if=/dev/ram0 of=/dev/null + +o echo [<string|$name> [<string|$name>...]] + + Copy the sequence of strings and expanded environment variables to + console out (or to a file if the output is re-directed). + +o exec <hex-address> + + Execute the user logic at address <hex-address>. NSH will pause + until the execution unless the user logic is executed in background + via 'exec <hex-address> &' + +o exit + + Exit NSH. Only useful if you have started some other tasks (perhaps + using the 'exec' command') and you would like to have NSH out of the + way. + +o free + + Show the current state of the memory allocator. For example, + + nsh> free + free + total used free largest + Mem: 4194288 1591552 2602736 2601584 + + Where: + total - This is the total size of memory allocated for use + by malloc in bytes. + used - This is the total size of memory occupied by + chunks handed out by malloc. + free - This is the total size of memory occupied by + free (not in use) chunks. + largest - Size of the largest free (not in use) chunk + +o get [-b|-n] [-f <local-path>] -h <ip-address> <remote-path> + + Use TFTP to copy the file at <remote-address> from the host whose IP + address is identified by <ip-address>. Other options: + + -f <local-path> + The file will be saved relative to the current working directory + unless <local-path> is provided. + -b|-n + Selects either binary ("octect") or test ("netascii") transfer + mode. Default: text. + +o help + + Presents summary information about each command to console. + +o ifconfig + + Show the current configuration of the network, for example: + + nsh> ifconfig + eth0 HWaddr 00:18:11:80:10:06 + IPaddr:10.0.0.2 DRaddr:10.0.0.1 Mask:255.255.255.0 + + if uIP statistics are enabled (CONFIG_NET_STATISTICS), then + this command will also show the detailed state of uIP. + +o kill -<signal> <pid> + + Send the <signal> to the task identified by <pid>. + +o losetup [-d <dev-path>] | [[-o <offset>] [-r] <ldev-path> <file-path>] + + Setup or teardown the loop device: + + 1. Teardown the setup for the loop device at <dev-path>: + + losetup d <dev-path> + + 2. Setup the loop device at <dev-path> to access the file at <file-path> + as a block device: + + losetup [-o <offset>] [-r] <dev-path> <file-path> + + Example: + + nsh> dd if=/dev/zero of=/tmp/image bs=512 count=512 + nsh> ls -l /tmp + /tmp: + -rw-rw-rw- 262144 IMAGE + nsh> losetup /dev/loop0 /tmp/image + nsh> ls -l /dev + /dev: + brw-rw-rw- 0 loop0 + nsh> mkfatfs /dev/loop0 + nsh> mount -t vfat /dev/loop0 /mnt/example + nsh> ls -l /mnt + ls -l /mnt + /mnt: + drw-rw-rw- 0 example/ + nsh> echo "This is a test" >/mnt/example/atest.txt + nsh> ls -l /mnt/example + /mnt/example: + -rw-rw-rw- 16 ATEST.TXT + nsh> cat /mnt/example/atest.txt + This is a test + nsh> + +o ls [-lRs] <dir-path> + + Show the contents of the directory at <dir-path>. NOTE: + <dir-path> must refer to a directory and no other filesystem + object. + + Options: + -------- + + -R Show the constents of specified directory and all of its + sub-directories. + -s Show the size of the files along with the filenames in the + listing + -l Show size and mode information along with the filenames + in the listing. + +o mb <hex-address>[=<hex-value>][ <hex-byte-count>] +o mh <hex-address>[=<hex-value>][ <hex-byte-count>] +o mw <hex-address>[=<hex-value>][ <hex-byte-count>] + + Access memory using byte size access (mb), 16-bit accesses (mh), + or 32-bit access (mw). In each case, + + <hex-address>. Specifies the address to be accessed. The current + value at that address will always be read and displayed. + <hex-address>=<hex-value>. Read the value, then write <hex-value> + to the location. + <hex-byte-count>. Perform the mb, mh, or mw operation on a total + of <hex-byte-count> bytes, increment the <hex-address> appropriately + after each access + + Example + + nsh> mh 0 16 + 0 = 0x0c1e + 2 = 0x0100 + 4 = 0x0c1e + 6 = 0x0110 + 8 = 0x0c1e + a = 0x0120 + c = 0x0c1e + e = 0x0130 + 10 = 0x0c1e + 12 = 0x0140 + 14 = 0x0c1e + nsh> + +o mkdir <path> + + Create the directory at <path>. All components of of <path> + except the final directory name must exist on a mounted file + system; the final directory must not. + + Recall that NuttX uses a pseudo filesystem for its root file system. + The mkdir command can only be used to create directories in volumes + set up with the mount command; it cannot be used to create directories + in the pseudo filesystem. + + Example: + ^^^^^^^^ + + nsh> mkdir /mnt/fs/tmp + nsh> ls -l /mnt/fs + /mnt/fs: + drw-rw-rw- 0 TESTDIR/ + drw-rw-rw- 0 TMP/ + nsh> + +o mkfatfs <path> + + Format a fat file system on the block device specified by path. + NSH provides this command to access the mkfatfs() NuttX API. + This block device must reside in the NuttX psuedo filesystem and + must have been created by some call to register_blockdriver() (see + include/nuttx/fs.h). + +o mkfifo <path> + + Creates a FIFO character device anywhere in the pseudo file system, + creating whatever psuedo directories that may be needed to complete + the full path. By convention, however, device drivers are place in + the standard /dev directory. After it is created, the FIFO device + may be used as any other device driver. NSH provides this command + to access the mkfifo() NuttX API. + + Example: + ^^^^^^^^ + + nsh> ls -l /dev + /dev: + crw-rw-rw- 0 console + crw-rw-rw- 0 null + brw-rw-rw- 0 ram0 + nsh> mkfifo /dev/fifo + nsh> ls -l /dev + ls -l /dev + /dev: + crw-rw-rw- 0 console + crw-rw-rw- 0 fifo + crw-rw-rw- 0 null + brw-rw-rw- 0 ram0 + nsh> + +o mkrd [-m <minor>] [-s <sector-size>] <nsectors> + + Create a ramdisk consisting of <nsectors>, each of size + <sector-size> (or 512 bytes if <sector-size> is not specified. + The ramdisk will be registered as /dev/ram<n> (if <n> is not + specified, mkrd will attempt to register the ramdisk as + /dev/ram0. + + Example: + ^^^^^^^^ + + nsh> ls /dev + /dev: + console + null + ttyS0 + ttyS1 + nsh> mkrd 1024 + nsh> ls /dev + /dev: + console + null + ram0 + ttyS0 + ttyS1 + nsh> + + Once the ramdisk has been created, it may be formatted using + the mkfatfs command and mounted using the mount command. + + Example: + ^^^^^^^^ + nsh> mkrd 1024 + nsh> mkfatfs /dev/ram0 + nsh> mount -t vfat /dev/ram0 /tmp + nsh> ls /tmp + /tmp: + nsh> + +o mount -t <fstype> <block-device> <dir-path> + + The 'mount' command mounts a file system in the NuttX psuedo + filesystem. 'mount' performs a three way associating, binding + + File system. The '-t <fstype>' option identifies the type of + file system that has been formatted on the <block-device>. As + of this writing, vfat is the only supported value for <fstype> + + Block Device. The <block-device> argument is the full or relative + path to a block driver inode in the psuedo filesystem. By convention, + this is a name under the /dev sub-directory. This <block-device> + must have been previously formatted with the same file system + type as specified by <fstype> + + Mount Point. The mount point is the location in the psuedo file + system where the mounted volume will appear. This mount point + can only reside in the NuttX psuedo filesystem. By convention, this + mount point is a subdirectory under /mnt. The mount command will + create whatever psuedo directories that may be needed to complete + the full path but the full path must not already exist. + + After the volume has been mounted in the NuttX psuedo file + system, it may be access in the same way as other objects in the + file system. + + Example: + ^^^^^^^^ + + nsh> ls -l /dev + /dev: + crw-rw-rw- 0 console + crw-rw-rw- 0 null + brw-rw-rw- 0 ram0 + nsh> ls /mnt + nsh: ls: no such directory: /mnt + nsh> mount -t vfat /dev/ram0 /mnt/fs + nsh> ls -l /mnt/fs/testdir + /mnt/fs/testdir: + -rw-rw-rw- 15 TESTFILE.TXT + nsh> echo "This is a test" >/mnt/fs/testdir/example.txt + nsh> ls -l /mnt/fs/testdir + /mnt/fs/testdir: + -rw-rw-rw- 15 TESTFILE.TXT + -rw-rw-rw- 16 EXAMPLE.TXT + nsh> cat /mnt/fs/testdir/example.txt + This is a test + nsh> + +o ps + + Show the currently active threads and tasks. For example, + + nsh> ps + PID PRI SCHD TYPE NP STATE NAME + 0 0 FIFO TASK READY Idle Task() + 1 128 RR TASK RUNNING init() + 2 128 FIFO TASK WAITSEM nsh_telnetmain() + 3 100 RR PTHREAD WAITSEM <pthread>(21) + nsh> + +o ping [-c <count>] [-i <interval>] <ip-address> + + Test the network communication with a remote peer. Example, + + nsh> 10.0.0.1 + PING 10.0.0.1 56 bytes of data + 56 bytes from 10.0.0.1: icmp_seq=1 time=0 ms + 56 bytes from 10.0.0.1: icmp_seq=2 time=0 ms + 56 bytes from 10.0.0.1: icmp_seq=3 time=0 ms + 56 bytes from 10.0.0.1: icmp_seq=4 time=0 ms + 56 bytes from 10.0.0.1: icmp_seq=5 time=0 ms + 56 bytes from 10.0.0.1: icmp_seq=6 time=0 ms + 56 bytes from 10.0.0.1: icmp_seq=7 time=0 ms + 56 bytes from 10.0.0.1: icmp_seq=8 time=0 ms + 56 bytes from 10.0.0.1: icmp_seq=9 time=0 ms + 56 bytes from 10.0.0.1: icmp_seq=10 time=0 ms + 10 packets transmitted, 10 received, 0% packet loss, time 10190 ms + nsh> + +o put [-b|-n] [-f <remote-path>] -h <ip-address> <local-path> + + Copy the file at <local-address> to the host whose IP address is + identified by <ip-address>. Other options: + + -f <remote-path> + The file will be saved with the same name on the host unless + unless <local-path> is provided. + -b|-n + Selects either binary ("octect") or test ("netascii") transfer + mode. Default: text. + +o pwd + + Show the current working directory. + + nsh> cd /dev + nsh> pwd + /dev + nsh> + + Same as 'echo $PWD' + + nsh> echo $PWD + /dev + nsh> + +o rm <file-path> + + Remove the specified <file-path> name from the mounted file system. + Recall that NuttX uses a pseudo filesystem for its root file system. + The rm command can only be used to remove (unlink) files in volumes + set up with the mount command; it cannot be used to remove names from + the pseudo filesystem. + + Example: + ^^^^^^^^ + + nsh> ls /mnt/fs/testdir + /mnt/fs/testdir: + TESTFILE.TXT + EXAMPLE.TXT + nsh> rm /mnt/fs/testdir/example.txt + nsh> ls /mnt/fs/testdir + /mnt/fs/testdir: + TESTFILE.TXT + nsh> + +o rmdir <dir-path> + + Remove the specified <dir-path> directory from the mounted file system. + Recall that NuttX uses a pseudo filesystem for its root file system. The + rmdir command can only be used to remove directories from volumes set up + with the mount command; it cannot be used to remove directories from the + pseudo filesystem. + + Example: + ^^^^^^^^ + + nsh> mkdir /mnt/fs/tmp + nsh> ls -l /mnt/fs + /mnt/fs: + drw-rw-rw- 0 TESTDIR/ + drw-rw-rw- 0 TMP/ + nsh> rmdir /mnt/fs/tmp + nsh> ls -l /mnt/fs + ls -l /mnt/fs + /mnt/fs: + drw-rw-rw- 0 TESTDIR/ + nsh> + +o set <name> <value> + + Set the environment variable <name> to the sting <value>. + For example, + + nsh> echo $foobar + + nsh> set foobar foovalue + nsh> echo $foobar + foovalue + nsh> + +o sh <script-path> + + Execute the sequence of NSH commands in the file referred + to by <script-path>. + +o sleep <sec> + + Pause execution (sleep) of <sec> seconds. + +o unset <name> + + Remove the value associated with the environment variable + <name>. Example: + + nsh> echo $foobar + foovalue + nsh> unset foobar + nsh> echo $foobar + + nsh> + +o usleep <usec> + + Pause execution (sleep) of <usec> microseconds. + +o wget [-o <local-path>] <url> + + Use HTTP to copy the file at <url> to the current directory. + Options: + + -o <local-path> + The file will be saved relative to the current working directory + and with the same name as on the HTTP server unless <local-path> + is provided. + +o xd <hex-address> <byte-count> + + Dump <byte-count> bytes of data from address <hex-address> + + Example: + ^^^^^^^^ + + nsh> xd 410e0 512 + Hex dump: + 0000: 00 00 00 00 9c 9d 03 00 00 00 00 01 11 01 10 06 ................ + 0010: 12 01 11 01 25 08 13 0b 03 08 1b 08 00 00 02 24 ....%..........$ + ... + 01f0: 08 3a 0b 3b 0b 49 13 00 00 04 13 01 01 13 03 08 .:.;.I.......... + nsh> + +NSH Configuration Settings +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The availability of the above commands depends upon features that +may or may not be enabled in the NuttX configuration file. The +following table indicates the dependency of each command on NuttX +configuration settings. General configuration settings are discussed +in the NuttX Porting Guide. Configuration settings specific to NSH +as discussed at the bottom of this README file. + +Command Dependencies on Configuration Settings +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Command Depends on Configuration + ---------- -------------------------- + [ !CONFIG_NSH_DISABLESCRIPT + cat CONFIG_NFILE_DESCRIPTORS > 0 + cd !CONFIG_DISABLE_ENVIRON && CONFIG_NFILE_DESCRIPTORS > 0 + cp CONFIG_NFILE_DESCRIPTORS > 0 + dd CONFIG_NFILE_DESCRIPTORS > 0 + echo -- + exec -- + exit -- + free -- + get CONFIG_NET && CONFIG_NET_UDP && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NET_BUFSIZE >= 558 (see note 1) + help -- + ifconfig CONFIG_NET + kill !CONFIG_DISABLE_SIGNALS + losetup !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 + ls CONFIG_NFILE_DESCRIPTORS > 0 + mb,mh,mw --- + mkdir !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4) + mkfatfs !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_FAT + mkfifo CONFIG_NFILE_DESCRIPTORS > 0 + mkrd !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4) + mount !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_READABLE (see note 3) + ping CONFIG_NET && CONFIG_NET_ICMP && CONFIG_NET_ICMP_PING && !CONFIG_DISABLE_CLOCK && !CONFIG_DISABLE_SIGNALS + ps -- + put CONFIG_NET && CONFIG_NET_UDP && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NET_BUFSIZE >= 558 (see note 1,2) + pwd !CONFIG_DISABLE_ENVIRON && CONFIG_NFILE_DESCRIPTORS > 0 + rm !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4) + rmdir !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4) + set !CONFIG_DISABLE_ENVIRON + sh CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !CONFIG_NSH_DISABLESCRIPT + sleep !CONFIG_DISABLE_SIGNALS + test !CONFIG_NSH_DISABLESCRIPT + umount !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_READABLE + unset !CONFIG_DISABLE_ENVIRON + usleep !CONFIG_DISABLE_SIGNALS + get CONFIG_NET && CONFIG_NET_TCP && CONFIG_NFILE_DESCRIPTORS > 0 + xd --- + +* NOTES: + 1. Because of hardware padding, the actual buffersize required for put and get + operations size may be larger. + 2. Special TFTP server start-up optionss will probably be required to permit + creation of file for the correct operation of the put command. + 3. CONFIG_FS_READABLE is not a user configuration but is set automatically + if any readable filesystem is selected. At present, this is either CONFIG_FS_FAT + and CONFIG_FS_ROMFS. + 4. CONFIG_FS_WRITABLE is not a user configuration but is set automatically + if any writable filesystem is selected. At present, this is only CONFIG_FS_FAT. + +In addition, each NSH command can be individually disabled via one of the following +settings. All of these settings make the configuration of NSH potentially complex but +also allow it to squeeze into very small memory footprints. + + CONFIG_NSH_DISABLE_CAT, CONFIG_NSH_DISABLE_CD, CONFIG_NSH_DISABLE_CP, + CONFIG_NSH_DISABLE_DD, CONFIG_NSH_DISABLE_ECHO, CONFIG_NSH_DISABLE_EXEC, + CONFIG_NSH_DISABLE_EXIT, CONFIG_NSH_DISABLE_FREE, CONFIG_NSH_DISABLE_GET, + CONFIG_NSH_DISABLE_HELP, CONFIG_NSH_DISABLE_IFCONFIG, CONFIG_NSH_DISABLE_KILL, + CONFIG_NSH_DISABLE_LOSETUP, CONFIG_NSH_DISABLE_LS, CONFIG_NSH_DISABLE_MB, + CONFIG_NSH_DISABLE_MKDIR, CONFIG_NSH_DISABLE_MKFATFS, CONFIG_NSH_DISABLE_MKFIFO, + CONFIG_NSH_DISABLE_MKRD, CONFIG_NSH_DISABLE_MH, CONFIG_NSH_DISABLE_MOUNT, + CONFIG_NSH_DISABLE_MW, CONFIG_NSH_DISABLE_PS, CONFIG_NSH_DISABLE_PING, + CONFIG_NSH_DISABLE_PUT, CONFIG_NSH_DISABLE_PWD, CONFIG_NSH_DISABLE_RM, + CONFIG_NSH_DISABLE_RMDIR, CONFIG_NSH_DISABLE_SET, CONFIG_NSH_DISABLE_SH, + CONFIG_NSH_DISABLE_SLEEP, CONFIG_NSH_DISABLE_TEST, CONFIG_NSH_DISABLE_UMOUNT, + CONFIG_NSH_DISABLE_UNSET, CONFIG_NSH_DISABLE_USLEEP, CONFIG_NSH_DISABLE_WGET, + CONFIG_NSH_DISABLE_XD + +NSH-Specific Configuration Settings +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + The behavior of NSH can be modified with the following settings in + the configs/<board-name>/defconfig file: + + * CONFIG_NSH_BUILTIN_APPS + Support external registered, "named" applications that can be + executed from the NSH command line (see apps/README.txt for + more information). + + * CONFIG_NSH_FILEIOSIZE + Size of a static I/O buffer used for file access (ignored if + there is no filesystem). Default is 1024. + + * CONFIG_NSH_STRERROR + strerror(errno) makes more readable output but strerror() is + very large and will not be used unless this setting is 'y' + + * CONFIG_NSH_LINELEN + The maximum length of one command line and of one output line. + Default: 80 + + * CONFIG_NSH_STACKSIZE + The stack size to use when spawning new threads or tasks. Such + new threads are generated when a command is executed in background + or as new TELNET connections are established. + + * CONFIG_NSH_NESTDEPTH + The maximum number of nested if-then[-else]-fi sequences that + are permissable. Default: 3 + + * CONFIG_NSH_DISABLESCRIPT + This can be set to 'y' to suppress support for scripting. This + setting disables the 'sh', 'test', and '[' commands and the + if-then[-else]-fi construct. This would only be set on systems + where a minimal footprint is a necessity and scripting is not. + + * CONFIG_NSH_DISABLEBG + This can be set to 'y' to suppress support for background + commands. This setting disables the 'nice' command prefix and + the '&' command suffix. This would only be set on systems + where a minimal footprint is a necessity and background command + execution is not. + + * CONFIG_NSH_MMCSDMINOR + If the architecture supports an MMC/SD slot and if the NSH + architecture specific logic is present, this option will provide + the MMC/SD minor number, i.e., the MMC/SD block driver will + be registered as /dev/mmcsdN where N is the minor number. + Default is zero. + + * CONFIG_NSH_ROMFSETC + Mount a ROMFS filesystem at /etc and provide a startup script + at /etc/init.d/rcS. The default startup script will mount + a FAT FS RAMDISK at /tmp but the logic is easily extensible. + + * CONFIG_NSH_CONSOLE + If CONFIG_NSH_CONSOLE is set to 'y', then a serial + console front-end is selected. + + * CONFIG_NSH_CONDEV + If CONFIG_NSH_CONSOLE is set to 'y', then CONFIG_NSH_CONDEV + may also be set to select the serial device used to support + the NSH console. This should be set to the quoted name of a + readable/write-able character driver such as: + CONFIG_NSH_CONDEV="/dev/ttyS1". This is useful, for example, + to separate the NSH command line from the system console when + the system console is used to provide debug output. Default: + stdin and stdout (probably "/dev/console") + + NOTE: When any other device other than /dev/console is used + for a user interface, (1) linefeeds (\n) will not be expanded to + carriage return / linefeeds (\r\n). You will need to set + your terminal program to account for this. And (2) input is + not automatically echoed so you will have to turn local echo on. + + * CONFIG_NSH_TELNET + If CONFIG_NSH_TELNET is set to 'y', then a TELENET + server front-end is selected. When this option is provided, + you may log into NuttX remotely using telnet in order to + access NSH. + + * CONFIG_NSH_ARCHINIT + Set if your board provides architecture specific initialization + via the board-specific function nsh_archinitialize(). This + function will be called early in NSH initialization to allow + board logic to do such things as configure MMC/SD slots. + + One or both of CONFIG_NSH_CONSOLE and CONFIG_NSH_TELNET + must be defined. If CONFIG_NSH_TELNET is selected, then there some + other configuration settings that apply: + + * CONFIG_NET=y + Of course, networking must be enabled + + * CONFIG_NSOCKET_DESCRIPTORS + And, of course, you must allocate some socket descriptors. + + * CONFIG_NET_TCP=y + TCP/IP support is required for telnet (as well as various other TCP-related + configuration settings). + + * CONFIG_NSH_IOBUFFER_SIZE + Determines the size of the I/O buffer to use for sending/ + receiving TELNET commands/reponses + + * CONFIG_NSH_DHCPC + Obtain the IP address via DHCP. + + * CONFIG_NSH_IPADDR + If CONFIG_NSH_DHCPC is NOT set, then the static IP + address must be provided. + + * CONFIG_NSH_DRIPADDR + Default router IP address + + * CONFIG_NSH_NETMASK + Network mask + + * CONFIG_NSH_NOMAC + Set if your ethernet hardware has no built-in MAC address. + If set, a bogus MAC will be assigned. + + If you use DHCPC, then some special configuration network options are + required. These include: + + * CONFIG_NET=y + Of course, networking must be enabled + + * CONFIG_NSOCKET_DESCRIPTORS + And, of course, you must allocate some socket descriptors. + + * CONFIG_NET_UDP=y + UDP support is required for DHCP (as well as various other UDP-related + configuration settings) + + * CONFIG_NET_BROADCAST=y + UDP broadcast support is needed. + + * CONFIG_NET_BUFSIZE=650 (or larger) + Per RFC2131 (p. 9), the DHCP client must be prepared to receive DHCP + messages of up to 576 bytes (excluding Ethernet, IP, or UDP headers and FCS). + + If CONFIG_NSH_ROMFSETC is selected, then the following additional + configuration setting apply: + + * CONFIG_NSH_ROMFSMOUNTPT + The default mountpoint for the ROMFS volume is /etc, but that + can be changed with this setting. This must be a absolute path + beginning with '/'. + + * CONFIG_NSH_INITSCRIPT + This is the relative path to the startup script within the mountpoint. + The default is init.d/rcS. This is a relative path and must not + start with '/'. + + * CONFIG_NSH_ROMFSDEVNO + This is the minor number of the ROMFS block device. The default is + '0' corresponding to /dev/ram0. + + * CONFIG_NSH_ROMFSSECTSIZE + This is the sector size to use with the ROMFS volume. Since the + default volume is very small, this defaults to 64 but should be + increased if the ROMFS volume were to be become large. Any value + selected must be a power of 2. + + When the default rcS file used when CONFIG_NSH_ROMFSETC is + selected, it will mount a FAT FS under /tmp. The following selections + describe that FAT FS. + + * CONFIG_NSH_FATDEVNO + This is the minor number of the FAT FS block device. The default is + '1' corresponding to /dev/ram1. + + * CONFIG_NSH_FATSECTSIZE + This is the sector size use with the FAT FS. Default is 512. + + * CONFIG_NSH_FATNSECTORS + This is the number of sectors to use with the FAT FS. Defalt is + 1024. The amount of memory used by the FAT FS will be + CONFIG_NSH_FATSECTSIZE * CONFIG_NSH_FATNSECTORS + bytes. + + * CONFIG_NSH_FATMOUNTPT + This is the location where the FAT FS will be mounted. Default + is /tmp. + +Common Problems +^^^^^^^^^^^^^^^ + + Problem: + Using NSH over serial, the "nsh>" prompt repeats over and over again + with no serial input. + Usual Cause: + NSH over serial needs to use the interrupt driven serial driver + (drivers/serial/serial.c) not the polled serial driver (drivers/serial/lowconsole.c). + Make sure that the polled console is disabled in the OS configuration + file, .config. That file should have CONFIG_DEV_LOWCONSOLE=n for + NSH over serial. diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h new file mode 100644 index 000000000..fd265982f --- /dev/null +++ b/apps/nshlib/nsh.h @@ -0,0 +1,497 @@ +/**************************************************************************** + * apps/nshlib/nsh.h + * + * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_NSHLIB_NSH_H +#define __APPS_NSHLIB_NSH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> + +#ifdef CONFIG_NSH_CONSOLE +# include <stdio.h> +#endif + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* The telnetd interface and background commands require pthread support */ + +#ifdef CONFIG_DISABLE_PTHREAD +# undef CONFIG_NSH_TELNET +# ifndef CONFIG_NSH_DISABLEBG +# define CONFIG_NSH_DISABLEBG 1 +# endif +#endif + +/* Telnetd requires networking support */ + +#ifndef CONFIG_NET +# undef CONFIG_NSH_TELNET +#endif + +/* One front end must be defined */ + +#if !defined(CONFIG_NSH_CONSOLE) && !defined(CONFIG_NSH_TELNET) +# error "No NSH front end defined" +#endif + +/* Verify support for ROMFS /etc directory support options */ + +#ifdef CONFIG_NSH_ROMFSETC +# ifdef CONFIG_DISABLE_MOUNTPOINT +# error "Mountpoint support is disabled" +# undef CONFIG_NSH_ROMFSETC +# endif +# if CONFIG_NFILE_DESCRIPTORS < 4 +# error "Not enough file descriptors" +# undef CONFIG_NSH_ROMFSETC +# endif +# ifndef CONFIG_FS_ROMFS +# error "ROMFS support not enabled" +# undef CONFIG_NSH_ROMFSETC +# endif +# ifndef CONFIG_NSH_ROMFSMOUNTPT +# define CONFIG_NSH_ROMFSMOUNTPT "/etc" +# endif +# ifdef CONFIG_NSH_INIT +# ifndef CONFIG_NSH_INITSCRIPT +# define CONFIG_NSH_INITSCRIPT "init.d/rcS" +# endif +# endif +# undef NSH_INITPATH +# define NSH_INITPATH CONFIG_NSH_ROMFSMOUNTPT "/" CONFIG_NSH_INITSCRIPT +# ifndef CONFIG_NSH_ROMFSDEVNO +# define CONFIG_NSH_ROMFSDEVNO 0 +# endif +# ifndef CONFIG_NSH_ROMFSSECTSIZE +# define CONFIG_NSH_ROMFSSECTSIZE 64 +# endif +# define NSECTORS(b) (((b)+CONFIG_NSH_ROMFSSECTSIZE-1)/CONFIG_NSH_ROMFSSECTSIZE) +# define STR_RAMDEVNO(m) #m +# define MKMOUNT_DEVNAME(m) "/dev/ram" STR_RAMDEVNO(m) +# define MOUNT_DEVNAME MKMOUNT_DEVNAME(CONFIG_NSH_ROMFSDEVNO) +#else +# undef CONFIG_NSH_ROMFSMOUNTPT +# undef CONFIG_NSH_INIT +# undef CONFIG_NSH_INITSCRIPT +# undef CONFIG_NSH_ROMFSDEVNO +# undef CONFIG_NSH_ROMFSSECTSIZE +#endif + +/* This is the maximum number of arguments that will be accepted for a command */ + +#define NSH_MAX_ARGUMENTS 6 + +/* strerror() produces much nicer output but is, however, quite large and + * will only be used if CONFIG_NSH_STRERROR is defined. + */ + +#ifdef CONFIG_NSH_STRERROR +# define NSH_ERRNO strerror(errno) +# define NSH_ERRNO_OF(err) strerror(err) +#else +# define NSH_ERRNO (errno) +# define NSH_ERRNO_OF(err) (err) +#endif + +/* Maximum size of one command line (telnet or serial) */ + +#ifndef CONFIG_NSH_LINELEN +# define CONFIG_NSH_LINELEN 80 +#endif + +/* The following two settings are used only in the telnetd interface */ + +#ifndef CONFIG_NSH_IOBUFFER_SIZE +# define CONFIG_NSH_IOBUFFER_SIZE 512 +#endif + +/* As threads are created to handle each request, a stack must be allocated + * for the thread. Use a default if the user provided no stacksize. + */ + +#ifndef CONFIG_NSH_STACKSIZE +# define CONFIG_NSH_STACKSIZE 4096 +#endif + +/* The maximum number of nested if-then[-else]-fi sequences that + * are permissable. + */ + +#ifndef CONFIG_NSH_NESTDEPTH +# define CONFIG_NSH_NESTDEPTH 3 +#endif + +/* Define to enable dumping of all input/output buffers */ + +#undef CONFIG_NSH_TELNETD_DUMPBUFFER +#undef CONFIG_NSH_FULLPATH + +/* Make sure that the home directory is defined */ + +#ifndef CONFIG_LIB_HOMEDIR +# define CONFIG_LIB_HOMEDIR "/" +#endif + +/* Method access macros */ + +#define nsh_clone(v) (v)->clone(v) +#define nsh_release(v) (v)->release(v) +#define nsh_write(v,b,n) (v)->write(v,b,n) +#define nsh_linebuffer(v) (v)->linebuffer(v) +#define nsh_redirect(v,f,s) (v)->redirect(v,f,s) +#define nsh_undirect(v,s) (v)->undirect(v,s) +#define nsh_exit(v) (v)->exit(v) + +#ifdef CONFIG_CPP_HAVE_VARARGS +# define nsh_output(v, fmt...) (v)->output(v, ##fmt) +#else +# define nsh_output vtbl->output +#endif + +/* Size of info to be saved in call to nsh_redirect */ + +#define SAVE_SIZE (sizeof(int) + sizeof(FILE*) + sizeof(bool)) + +/* Stubs used when working directory is not supported */ + +#if CONFIG_NFILE_DESCRIPTORS <= 0 || defined(CONFIG_DISABLE_ENVIRON) +# define nsh_getfullpath(v,p) ((char*)(p)) +# define nsh_freefullpath(p) +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum nsh_parser_e +{ + NSH_PARSER_NORMAL = 0, + NSH_PARSER_IF, + NSH_PARSER_THEN, + NSH_PARSER_ELSE +}; + +struct nsh_state_s +{ + uint8_t ns_ifcond : 1; /* Value of command in 'if' statement */ + uint8_t ns_disabled : 1; /* TRUE: Unconditionally disabled */ + uint8_t ns_unused : 4; + uint8_t ns_state : 2; /* Parser state (see enum nsh_parser_e) */ +}; + +struct nsh_parser_s +{ +#ifndef CONFIG_NSH_DISABLEBG + bool np_bg; /* true: The last command executed in background */ +#endif + bool np_redirect; /* true: Output from the last command was re-directed */ + bool np_fail; /* true: The last command failed */ +#ifndef CONFIG_NSH_DISABLESCRIPT + uint8_t np_ndx; /* Current index into np_st[] */ +#endif +#ifndef CONFIG_NSH_DISABLEBG + int np_nice; /* "nice" value applied to last background cmd */ +#endif + + /* This is a stack of parser state information. It supports nested + * execution of commands that span multiple lines (like if-then-else-fi) + */ + +#ifndef CONFIG_NSH_DISABLESCRIPT + struct nsh_state_s np_st[CONFIG_NSH_NESTDEPTH]; +#endif +}; + +struct nsh_vtbl_s +{ + /* This function pointers are "hooks" into the front end logic to + * handle things like output of command results, redirection, etc. + * -- all of which must be done in a way that is unique to the nature + * of the front end. + */ + +#ifndef CONFIG_NSH_DISABLEBG + FAR struct nsh_vtbl_s *(*clone)(FAR struct nsh_vtbl_s *vtbl); + void (*addref)(FAR struct nsh_vtbl_s *vtbl); + void (*release)(FAR struct nsh_vtbl_s *vtbl); +#endif + ssize_t (*write)(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes); + int (*output)(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); + FAR char *(*linebuffer)(FAR struct nsh_vtbl_s *vtbl); + void (*redirect)(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save); + void (*undirect)(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save); + void (*exit)(FAR struct nsh_vtbl_s *vtbl); + + /* Parser state data */ + + struct nsh_parser_s np; +}; + +typedef int (*cmd_t)(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern const char g_nshgreeting[]; +extern const char g_nshprompt[]; +extern const char g_nshsyntax[]; +extern const char g_fmtargrequired[]; +extern const char g_fmtarginvalid[]; +extern const char g_fmtargrange[]; +extern const char g_fmtcmdnotfound[]; +extern const char g_fmtnosuch[]; +extern const char g_fmttoomanyargs[]; +extern const char g_fmtdeepnesting[]; +extern const char g_fmtcontext[]; +extern const char g_fmtcmdfailed[]; +extern const char g_fmtcmdoutofmemory[]; +extern const char g_fmtinternalerror[]; +#ifndef CONFIG_DISABLE_SIGNALS +extern const char g_fmtsignalrecvd[]; +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Initialization */ + +#ifdef CONFIG_NSH_ROMFSETC +extern int nsh_romfsetc(void); +#else +# define nsh_romfsetc() (-ENOSYS) +#endif + +#ifdef CONFIG_NET +extern int nsh_netinit(void); +#else +# define nsh_netinit() (-ENOSYS) +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) +extern int nsh_script(FAR struct nsh_vtbl_s *vtbl, const char *cmd, const char *path); +#endif + +/* Architecture-specific initialization */ + +#ifdef CONFIG_NSH_ARCHINIT +extern int nsh_archinitialize(void); +#else +# define nsh_archinitialize() (-ENOSYS) +#endif + +/* Message handler */ + +extern int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline); + +/* Application interface */ + +#ifdef CONFIG_NSH_BUILTIN_APPS +extern int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, + FAR char **argv); +#endif + +/* Working directory support */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +extern FAR const char *nsh_getcwd(void); +extern char *nsh_getfullpath(FAR struct nsh_vtbl_s *vtbl, const char *relpath); +extern void nsh_freefullpath(char *relpath); +#endif + +/* Debug */ + +extern void nsh_dumpbuffer(FAR struct nsh_vtbl_s *vtbl, const char *msg, + const uint8_t *buffer, ssize_t nbytes); + +/* Shell command handlers */ + +#ifndef CONFIG_NSH_DISABLE_ECHO + extern int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_EXEC + extern int cmd_exec(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_MB + extern int cmd_mb(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_MH + extern int cmd_mh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_MW + extern int cmd_mw(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_FREE + extern int cmd_free(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_PS + extern int cmd_ps(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +#ifndef CONFIG_NSH_DISABLE_XD + extern int cmd_xd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif + +#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_TEST) +extern int cmd_test(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +extern int cmd_lbracket(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif + +#ifndef CONFIG_DISABLE_CLOCK +# if defined (CONFIG_RTC) && !defined(CONFIG_NSH_DISABLE_DATE) +extern int cmd_date(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_CAT + extern int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_CP + extern int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_DD + extern int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_LS + extern int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# if CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) +# ifndef CONFIG_NSH_DISABLE_SH + extern int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# endif /* CONFIG_NFILE_STREAMS && !CONFIG_NSH_DISABLESCRIPT */ +# ifndef CONFIG_DISABLE_MOUNTPOINT +# ifndef CONFIG_NSH_DISABLE_LOSETUP + extern int cmd_losetup(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_MKFIFO + extern int cmd_mkfifo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifdef CONFIG_FS_READABLE +# ifndef CONFIG_NSH_DISABLE_MOUNT + extern int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_UMOUNT + extern int cmd_umount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifdef CONFIG_FS_WRITABLE +# ifndef CONFIG_NSH_DISABLE_MKDIR + extern int cmd_mkdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_MKRD + extern int cmd_mkrd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_RM + extern int cmd_rm(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_RMDIR + extern int cmd_rmdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# endif /* CONFIG_FS_WRITABLE */ +# endif /* CONFIG_FS_READABLE */ +# ifdef CONFIG_FS_FAT +# ifndef CONFIG_NSH_DISABLE_MKFATFS + extern int cmd_mkfatfs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# endif /* CONFIG_FS_FAT */ +# endif /* !CONFIG_DISABLE_MOUNTPOINT */ +# if !defined(CONFIG_DISABLE_ENVIRON) +# ifndef CONFIG_NSH_DISABLE_CD + extern int cmd_cd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_PWD + extern int cmd_pwd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# endif /* !CONFIG_DISABLE_MOUNTPOINT */ +#endif /* CONFIG_NFILE_DESCRIPTORS */ + +#if defined(CONFIG_NET) +# ifndef CONFIG_NSH_DISABLE_IFCONFIG + extern int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_GET + extern int cmd_get(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_PUT + extern int cmd_put(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif +#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_WGET + extern int cmd_wget(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif +#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ + !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS) +# ifndef CONFIG_NSH_DISABLE_PING + extern int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif +#endif + +#ifndef CONFIG_DISABLE_ENVIRON +# ifndef CONFIG_NSH_DISABLE_SET + extern int cmd_set(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_UNSET + extern int cmd_unset(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif /* CONFIG_DISABLE_ENVIRON */ + +#ifndef CONFIG_DISABLE_SIGNALS +# ifndef CONFIG_NSH_DISABLE_KILL + extern int cmd_kill(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_SLEEP + extern int cmd_sleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +# ifndef CONFIG_NSH_DISABLE_USLEEP + extern int cmd_usleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +# endif +#endif /* CONFIG_DISABLE_SIGNALS */ + +#endif /* __APPS_NSHLIB_NSH_H */ diff --git a/apps/nshlib/nsh_apps.c b/apps/nshlib/nsh_apps.c new file mode 100644 index 000000000..d70c0d10f --- /dev/null +++ b/apps/nshlib/nsh_apps.c @@ -0,0 +1,120 @@ +/**************************************************************************** + * apps/nshlib/nsh_apps.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise <uros.platise@isotel.eu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#ifdef CONFIG_SCHED_WAITPID +# include <sys/wait.h> +#endif + +#include <stdbool.h> +#include <errno.h> +#include <string.h> + +#include <apps/apps.h> + +#include "nsh.h" + +#ifdef CONFIG_NSH_BUILTIN_APPS + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_execute + ****************************************************************************/ + +int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, + FAR char **argv) +{ + int ret = OK; + + /* Try to find command within pre-built application list. */ + + ret = exec_namedapp(cmd, (FAR const char **)argv); + if (ret < 0) + { + return -errno; + } + +#ifdef CONFIG_SCHED_WAITPID + if (vtbl->np.np_bg == false) + { + waitpid(ret, NULL, 0); + } + else +#endif + { + struct sched_param param; + sched_getparam(0, ¶m); + nsh_output(vtbl, "%s [%d:%d]\n", cmd, ret, param.sched_priority); + } + + return OK; +} + +#endif /* CONFIG_NSH_BUILTIN_APPS */ + + diff --git a/apps/nshlib/nsh_dbgcmds.c b/apps/nshlib/nsh_dbgcmds.c new file mode 100644 index 000000000..e9d6d9dab --- /dev/null +++ b/apps/nshlib/nsh_dbgcmds.c @@ -0,0 +1,355 @@ +/**************************************************************************** + * apps/nshlib/dbg_dbgcmds.c + * + * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct dbgmem_s +{ + bool dm_write; /* true: perfrom write operation */ + void *dm_addr; /* Address to access */ + uint32_t dm_value; /* Value to write */ + unsigned int dm_count; /* The number of bytes to access */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mem_parse + ****************************************************************************/ + +int mem_parse(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv, + struct dbgmem_s *mem) +{ + char *pcvalue = strchr(argv[1], '='); + unsigned long lvalue = 0; + + /* Check if we are writing a value */ + + if (pcvalue) + { + *pcvalue = '\0'; + pcvalue++; + + lvalue = (unsigned long)strtol(pcvalue, NULL, 16); + if (lvalue > 0xffffffff) + { + return -EINVAL; + } + + mem->dm_write = true; + mem->dm_value = (uint32_t)lvalue; + } + else + { + mem->dm_write = false; + mem->dm_value = 0; + } + + /* Get the address to be accessed */ + + mem->dm_addr = (void*)((uintptr_t)strtol(argv[1], NULL, 16)); + + /* Get the number of bytes to access */ + + if (argc > 2) + { + mem->dm_count = (unsigned int)strtol(argv[2], NULL, 16); + } + else + { + mem->dm_count = 1; + } + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_mb + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_MB +int cmd_mb(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct dbgmem_s mem; + volatile uint8_t *ptr; + int ret; + int i; + + ret = mem_parse(vtbl, argc, argv, &mem); + if (ret == 0) + { + /* Loop for the number of requested bytes */ + + for (i = 0, ptr = (volatile uint8_t*)mem.dm_addr; i < mem.dm_count; i++, ptr++) + { + /* Print the value at the address */ + + nsh_output(vtbl, " %p = 0x%02x", ptr, *ptr); + + /* Are we supposed to write a value to this address? */ + + if (mem.dm_write) + { + /* Yes, was the supplied value within range? */ + + if (mem.dm_value > 0x000000ff) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + return ERROR; + } + + /* Write the value and re-read the address so that we print its + * current value (if the address is a process address, then the + * value read might not necessarily be the value written). + */ + + *ptr = (uint8_t)mem.dm_value; + nsh_output(vtbl, " -> 0x%02x", *ptr); + } + + /* Make sure we end it with a newline */ + + nsh_output(vtbl, "\n", *ptr); + } + } + return ret; +} +#endif + +/**************************************************************************** + * Name: cmd_mh + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_MH +int cmd_mh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct dbgmem_s mem; + volatile uint16_t *ptr; + int ret; + int i; + + ret = mem_parse(vtbl, argc, argv, &mem); + if (ret == 0) + { + /* Loop for the number of requested bytes */ + + for (i = 0, ptr = (volatile uint16_t*)mem.dm_addr; i < mem.dm_count; i += 2, ptr++) + { + /* Print the value at the address */ + + nsh_output(vtbl, " %p = 0x%04x", ptr, *ptr); + + /* Are we supposed to write a value to this address? */ + + if (mem.dm_write) + { + /* Yes, was the supplied value within range? */ + + if (mem.dm_value > 0x0000ffff) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + return ERROR; + } + + /* Write the value and re-read the address so that we print its + * current value (if the address is a process address, then the + * value read might not necessarily be the value written). + */ + + *ptr = (uint16_t)mem.dm_value; + nsh_output(vtbl, " -> 0x%04x", *ptr); + } + + /* Make sure we end it with a newline */ + + nsh_output(vtbl, "\n", *ptr); + } + } + return ret; +} +#endif + +/**************************************************************************** + * Name: cmd_mw + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_MW +int cmd_mw(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct dbgmem_s mem; + volatile uint32_t *ptr; + int ret; + int i; + + ret = mem_parse(vtbl, argc, argv, &mem); + if (ret == 0) + { + /* Loop for the number of requested bytes */ + + for (i = 0, ptr = (volatile uint32_t*)mem.dm_addr; i < mem.dm_count; i += 4, ptr++) + { + /* Print the value at the address */ + + nsh_output(vtbl, " %p = 0x%08x", ptr, *ptr); + + /* Are we supposed to write a value to this address? */ + + if (mem.dm_write) + { + /* Write the value and re-read the address so that we print its + * current value (if the address is a process address, then the + * value read might not necessarily be the value written). + */ + + *ptr = mem.dm_value; + nsh_output(vtbl, " -> 0x%08x", *ptr); + } + + /* Make sure we end it with a newline */ + + nsh_output(vtbl, "\n", *ptr); + } + } + return ret; +} +#endif + +/**************************************************************************** + * Name: nsh_dumpbuffer + ****************************************************************************/ + +void nsh_dumpbuffer(FAR struct nsh_vtbl_s *vtbl, const char *msg, + const uint8_t *buffer, ssize_t nbytes) +{ + char line[128]; + int ch; + int i; + int j; + + nsh_output(vtbl, "%s:\n", msg); + for (i = 0; i < nbytes; i += 16) + { + sprintf(line, "%04x: ", i); + + for ( j = 0; j < 16; j++) + { + if (i + j < nbytes) + { + sprintf(&line[strlen(line)], "%02x ", buffer[i+j] ); + } + else + { + strcpy(&line[strlen(line)], " "); + } + } + + for ( j = 0; j < 16; j++) + { + if (i + j < nbytes) + { + ch = buffer[i+j]; + sprintf(&line[strlen(line)], "%c", ch >= 0x20 && ch <= 0x7e ? ch : '.'); + } + } + nsh_output(vtbl, "%s\n", line); + } +} + +/**************************************************************************** + * Name: cmd_xd + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_XD +int cmd_xd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + FAR char *addr; + FAR char *endptr; + int nbytes; + + addr = (char*)((uintptr_t)strtol(argv[1], &endptr, 16)); + if (argv[0][0] == '\0' || *endptr != '\0') + { + return ERROR; + } + + nbytes = (int)strtol(argv[2], &endptr, 0); + if (argv[0][0] == '\0' || *endptr != '\0' || nbytes < 0) + { + return ERROR; + } + + nsh_dumpbuffer(vtbl, "Hex dump", (uint8_t*)addr, nbytes); + return OK; +} +#endif + diff --git a/apps/nshlib/nsh_ddcmd.c b/apps/nshlib/nsh_ddcmd.c new file mode 100644 index 000000000..11652fe7e --- /dev/null +++ b/apps/nshlib/nsh_ddcmd.c @@ -0,0 +1,640 @@ +/**************************************************************************** + * apps/nshlib/nsh_ddcmd.c + * + * Copyright (C) 2008-2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/fs.h> +#include "nsh.h" + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_NSH_DISABLE_DD) + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* If no sector size is specified wity BS=, then the following default value + * is used. + */ + +#define DEFAULT_SECTSIZE 512 + +/* At present, piping of input and output are not support, i.e., both of= + * and if= arguments are required. + */ + +#undef CAN_PIPE_FROM_STD + +/* Function pointer calls are only need if block drivers are supported + * (or, rather, if mount points are supported in the file system) + */ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +# define DD_INFD ((dd)->inf.fd) +# define DD_INHANDLE ((dd)->inf.handle) +# define DD_OUTFD ((dd)->outf.fd) +# define DD_OUTHANDLE ((dd)->outf.handle) +# define DD_READ(dd) ((dd)->infread(dd)) +# define DD_WRITE(dd) ((dd)->outfwrite(dd)) +# define DD_INCLOSE(dd) ((dd)->infclose(dd)) +# define DD_OUTCLOSE(dd) ((dd)->outfclose(dd)) +#else +# define DD_INFD ((dd)->infd) +# undef DD_INHANDLE +# define DD_OUTFD ((dd)->outfd) +# undef DD_OUTHANDLE +# define DD_READ(dd) dd_readch(dd) +# define DD_WRITE(dd) dd_writech(dd) +# define DD_INCLOSE(dd) dd_infclosech(dd) +# define DD_OUTCLOSE(dd) dd_outfclosech(dd) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct dd_s +{ + FAR struct nsh_vtbl_s *vtbl; + +#ifndef CONFIG_DISABLE_MOUNTPOINT + union + { + FAR void *handle; /* BCH lib handle for block device*/ + int fd; /* File descriptor of the character device */ + } inf; +#else + int infd; /* File descriptor of the input device */ +#endif + +#ifndef CONFIG_DISABLE_MOUNTPOINT + union + { + FAR void *handle; /* BCH lib handle for block device*/ + int fd; /* File descriptor of the character device */ + } outf; +#else + int outfd; /* File descriptor of the output device */ +#endif + + uint32_t nsectors; /* Number of sectors to transfer */ + uint32_t sector; /* The current sector number */ + uint32_t skip; /* The number of sectors skipped on input */ + bool eof; /* true: The of the input or output file has been hit */ + uint16_t sectsize; /* Size of one sector */ + uint16_t nbytes; /* Number of valid bytes in the buffer */ + uint8_t *buffer; /* Buffer of data to write to the output file */ + + /* Function pointers to handle differences between block and character devices */ + +#ifndef CONFIG_DISABLE_MOUNTPOINT + int (*infread)(struct dd_s *dd); + void (*infclose)(struct dd_s *dd); + int (*outfwrite)(struct dd_s *dd); + void (*outfclose)(struct dd_s *dd); +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_dd[] = "dd"; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dd_outfcloseblk + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +static void dd_outfcloseblk(struct dd_s *dd) +{ + (void)bchlib_teardown(DD_OUTHANDLE); +} +#endif + + +/**************************************************************************** + * Name: dd_outfclosech + ****************************************************************************/ + +static void dd_outfclosech(struct dd_s *dd) +{ + (void)close(DD_OUTFD); +} + +/**************************************************************************** + * Name: dd_infcloseblk + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +static void dd_infcloseblk(struct dd_s *dd) +{ + (void)bchlib_teardown(DD_INHANDLE); +} +#endif + +/**************************************************************************** + * Name: dd_infclosech + ****************************************************************************/ + +static void dd_infclosech(struct dd_s *dd) +{ + (void)close(DD_INFD); +} + +/**************************************************************************** + * Name: dd_writeblk + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +static int dd_writeblk(struct dd_s *dd) +{ + ssize_t nbytes; + off_t offset = (dd->sector - dd->skip) * dd->sectsize; + + /* Write the sector at the specified offset */ + + nbytes = bchlib_write(DD_OUTHANDLE, (char*)dd->buffer, offset, dd->sectsize); + if (nbytes < 0) + { + /* bchlib_write return -EFBIG on attempts to write past the end of + * the device. + */ + + if (nbytes == -EFBIG) + { + dd->eof = true; /* Set end-of-file */ + } + else + { + FAR struct nsh_vtbl_s *vtbl = dd->vtbl; + nsh_output(vtbl, g_fmtcmdfailed, g_dd, "bshlib_write", NSH_ERRNO_OF(-nbytes)); + return ERROR; + } + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: dd_writech + ****************************************************************************/ + +static int dd_writech(struct dd_s *dd) +{ + uint8_t *buffer = dd->buffer; + uint16_t written ; + ssize_t nbytes; + + /* Is the out buffer full (or is this the last one)? */ + + written = 0; + do + { + nbytes = write(DD_OUTFD, buffer, dd->sectsize - written); + if (nbytes < 0) + { + FAR struct nsh_vtbl_s *vtbl = dd->vtbl; + nsh_output(vtbl, g_fmtcmdfailed, g_dd, "write", NSH_ERRNO_OF(-nbytes)); + return ERROR; + } + + written += nbytes; + buffer += nbytes; + } + while (written < dd->sectsize); + + return OK; +} + +/**************************************************************************** + * Name: dd_readblk + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +static int dd_readblk(struct dd_s *dd) +{ + ssize_t nbytes; + off_t offset = dd->sector * dd->sectsize; + + nbytes = bchlib_read(DD_INHANDLE, (char*)dd->buffer, offset, dd->sectsize); + if (nbytes < 0) + { + FAR struct nsh_vtbl_s *vtbl = dd->vtbl; + nsh_output(vtbl, g_fmtcmdfailed, g_dd, "bshlib_read", NSH_ERRNO_OF(-nbytes)); + return ERROR; + } + + /* bchlib_read return 0 on attempts to write past the end of the device. */ + + dd->nbytes = nbytes; + dd->eof = (nbytes == 0); + return OK; +} +#endif + +/**************************************************************************** + * Name: dd_readch + ****************************************************************************/ + +static int dd_readch(struct dd_s *dd) +{ + uint8_t *buffer = dd->buffer; + ssize_t nbytes; + + dd->nbytes = 0; + do + { + nbytes = read(DD_INFD, buffer, dd->sectsize - dd->nbytes); + if (nbytes < 0) + { + FAR struct nsh_vtbl_s *vtbl = dd->vtbl; + nsh_output(vtbl, g_fmtcmdfailed, g_dd, "read", NSH_ERRNO_OF(-nbytes)); + return ERROR; + } + + dd->nbytes += nbytes; + buffer += nbytes; + } + while (dd->nbytes < dd->sectsize && nbytes > 0); + + dd->eof |= (dd->nbytes == 0); + return OK; +} + +/**************************************************************************** + * Name: dd_infopen + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +static int dd_filetype(const char *filename) +{ + struct stat sb; + int ret; + + /* Get the type of the file */ + + ret = stat(filename, &sb); + if (ret < 0) + { + return ERROR; /* Return -1 on failure */ + } + + return S_ISBLK(sb.st_mode); /* Return true(1) if block, false(0) if char */ +} +#endif + +/**************************************************************************** + * Name: dd_infopen + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +static inline int dd_infopen(const char *name, struct dd_s *dd) +{ + FAR struct nsh_vtbl_s *vtbl = dd->vtbl; + int ret; + int type; + + /* Get the type of the input file */ + + type = dd_filetype(name); + if (type < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, g_dd, "stat", NSH_ERRNO_OF(-type)); + return type; + } + + /* Open the input file */ + + if (!type) + { + DD_INFD = open(name, O_RDONLY); + if (DD_INFD < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO); + return ERROR; + } + + dd->infread = dd_readch; /* Character oriented read */ + dd->infclose = dd_infclosech; + } + else + { + ret = bchlib_setup(name, true, &DD_INHANDLE); + if (ret < 0) + { + return ERROR; + } + + dd->infread = dd_readblk; + dd->infclose = dd_infcloseblk; + } + return OK; +} +#else +static inline int dd_infopen(const char *name, struct dd_s *dd) +{ + DD_INFD = open(name, O_RDONLY); + if (DD_INFD < 0) + { + FAR struct nsh_vtbl_s *vtbl = dd->vtbl; + nsh_output(vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO); + return ERROR; + } + return OK; +} +#endif + +/**************************************************************************** + * Name: dd_outfopen + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +static inline int dd_outfopen(const char *name, struct dd_s *dd) +{ + int type; + int ret = OK; + + /* Get the type of the output file */ + + type = dd_filetype(name); + + /* Open the block driver for input */ + + if (type == true) + { + ret = bchlib_setup(name, true, &DD_OUTHANDLE); + if (ret < 0) + { + return ERROR; + } + + dd->outfwrite = dd_writeblk; /* Block oriented write */ + dd->outfclose = dd_outfcloseblk; + } + + /* Otherwise, the file is character oriented or does not exist */ + + else + { + DD_OUTFD = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (DD_OUTFD < 0) + { + FAR struct nsh_vtbl_s *vtbl = dd->vtbl; + nsh_output(vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO); + return ERROR; + } + + dd->outfwrite = dd_writech; /* Character oriented write */ + dd->outfclose = dd_outfclosech; + } + return OK; +} +#else +static inline int dd_outfopen(const char *name, struct dd_s *dd) +{ + DD_OUTFD = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (DD_OUTFD < 0) + { + nsh_output(dd->vtbl, g_fmtcmdfailed, g_dd, "open", NSH_ERRNO); + return ERROR; + } + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_dd + ****************************************************************************/ + +int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct dd_s dd; + char *infile = NULL; + char *outfile = NULL; + int ret = ERROR; + int i; + + /* Initialize the dd structure */ + + memset(&dd, 0, sizeof(struct dd_s)); + dd.vtbl = vtbl; /* For nsh_output */ + dd.sectsize = DEFAULT_SECTSIZE; /* Sector size if 'bs=' not provided */ + dd.nsectors = 0xffffffff; /* MAX_UINT32 */ + + /* If no IF= option is provided on the command line, then read + * from stdin. + */ + +#ifdef CAN_PIPE_FROM_STD + DD_INFD = 0; /* stdin */ +#ifndef CONFIG_NSH_DISABLE_DD + dd.infread = readch; /* Character oriented read */ + dd.infclose = noclose; /* Don't close stdin */ +#endif +#endif + /* If no OF= option is provided on the command line, then write + * to stdout. + */ + +#ifdef CAN_PIPE_FROM_STD + DD_OUTDF = 1; /* stdout */ +#ifndef CONFIG_NSH_DISABLE_DD + dd.outfwrite = writech; /* Character oriented write */ + dd.outfclose = noclose; /* Don't close stdout */ +#endif +#endif + + /* Parse command line parameters */ + + for (i = 1; i < argc; i++) + { + if (strncmp(argv[i], "if=", 3) == 0) + { + infile = nsh_getfullpath(vtbl, &argv[i][3]); + } + else if (strncmp(argv[i], "of=", 3) == 0) + { + outfile = nsh_getfullpath(vtbl, &argv[i][3]); + } + else if (strncmp(argv[i], "bs=", 3) == 0) + { + dd.sectsize = atoi(&argv[i][3]); + } + else if (strncmp(argv[i], "count=", 6) == 0) + { + dd.nsectors = atoi(&argv[i][6]); + } + else if (strncmp(argv[i], "skip=", 5) == 0) + { + dd.skip = atoi(&argv[i][5]); + } + } + +#ifndef CAN_PIPE_FROM_STD + if (!infile || !outfile) + { + nsh_output(vtbl, g_fmtargrequired, g_dd); + goto errout_with_paths; + } +#endif + + if (dd.skip < 0 || dd.skip > dd.nsectors) + { + nsh_output(vtbl, g_fmtarginvalid, g_dd); + goto errout_with_paths; + } + + /* Allocate the I/O buffer */ + + dd.buffer = malloc(dd.sectsize); + if (!dd.buffer) + { + nsh_output(vtbl, g_fmtcmdoutofmemory, g_dd); + goto errout_with_paths; + } + + /* Open the input file */ + + ret = dd_infopen(infile, &dd); + if (ret < 0) + { + goto errout_with_paths; + } + + /* Open the output file */ + + ret = dd_outfopen(outfile, &dd); + if (ret < 0) + { + goto errout_with_inf; + } + + /* Then perform the data transfer */ + + dd.sector = 0; + while (!dd.eof && dd.nsectors > 0) + { + /* Read one sector from from the input */ + + ret = DD_READ(&dd); + if (ret < 0) + { + goto errout_with_outf; + } + + /* Has the incoming data stream ended? */ + + if (!dd.eof) + { + /* Pad with zero if necessary (at the end of file only) */ + + for (i = dd.nbytes; i < dd.sectsize; i++) + { + dd.buffer[i] = 0; + } + + /* Write one sector to the output file */ + + if (dd.sector >= dd.skip) + { + ret = DD_WRITE(&dd); + if (ret < 0) + { + goto errout_with_outf; + } + + /* Decrement to show that a sector was written */ + + dd.nsectors--; + } + + /* Increment the sector number */ + + dd.sector++; + } + } + ret = OK; + +errout_with_outf: + DD_INCLOSE(&dd); +errout_with_inf: + DD_OUTCLOSE(&dd); + free(dd.buffer); +errout_with_paths: + if (infile) + { + free(infile); + } + if (outfile) + { + free(outfile); + } + return ret; +} + +#endif /* CONFIG_NFILE_DESCRIPTORS && !CONFIG_NSH_DISABLE_DD */ + diff --git a/apps/nshlib/nsh_envcmds.c b/apps/nshlib/nsh_envcmds.c new file mode 100644 index 000000000..520dd76e7 --- /dev/null +++ b/apps/nshlib/nsh_envcmds.c @@ -0,0 +1,336 @@ +/**************************************************************************** + * apps/nshlib/nsh_envcmds.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <libgen.h> +#include <errno.h> + +#include "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +static const char g_pwd[] = "PWD"; +static const char g_oldpwd[] = "OLDPWD"; +static const char g_home[] = CONFIG_LIB_HOMEDIR; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_getwd + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +static inline FAR const char *nsh_getwd(const char *wd) +{ + const char *val; + + /* If no working directory is defined, then default to the home directory */ + + val = getenv(wd); + if (!val) + { + val = g_home; + } + return val; +} +#endif + +/**************************************************************************** + * Name: nsh_getdirpath + ****************************************************************************/ + +static inline char *nsh_getdirpath(FAR struct nsh_vtbl_s *vtbl, + const char *dirpath, const char *relpath) +{ + char *alloc; + int len; + + /* Handle the special case where the dirpath is simply */ + + if (strcmp(dirpath, "/") == 0) + { + len = strlen(relpath) + 2; + alloc = (char*)malloc(len); + if (alloc) + { + sprintf(alloc, "/%s", relpath); + } + } + else + { + len = strlen(dirpath) + strlen(relpath) + 2; + alloc = (char*)malloc(len); + if (alloc) + { + sprintf(alloc, "%s/%s", dirpath, relpath); + } + } + + if (!alloc) + { + nsh_output(vtbl, g_fmtcmdoutofmemory, "nsh_getdirpath"); + } + return alloc; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_getwd + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +FAR const char *nsh_getcwd(void) +{ + return nsh_getwd(g_pwd); +} +#endif +/**************************************************************************** + * Name: nsh_getfullpath + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +char *nsh_getfullpath(FAR struct nsh_vtbl_s *vtbl, const char *relpath) +{ + const char *wd; + + /* Handle some special cases */ + + if (!relpath || relpath[0] == '\0') + { + /* No relative path provided */ + + return strdup(g_home); + } + else if (relpath[0] == '/') + { + return strdup(relpath); + } + + /* Get the path to the current working directory */ + + wd = nsh_getcwd(); + + /* Fake the '.' directory */ + + if (strcmp(relpath, ".") == 0) + { + return strdup(wd); + } + + /* Return the full path */ + + return nsh_getdirpath(vtbl, wd, relpath); +} +#endif + +/**************************************************************************** + * Name: nsh_freefullpath + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +void nsh_freefullpath(char *relpath) +{ + if (relpath) + { + free(relpath); + } +} +#endif + +/**************************************************************************** + * Name: cmd_cd + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +#ifndef CONFIG_NSH_DISABLE_CD +int cmd_cd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + const char *path = argv[1]; + char *alloc = NULL; + char *fullpath = NULL; + int ret = OK; + + /* Check for special arguments */ + + if (argc < 2 || strcmp(path, "~") == 0) + { + path = g_home; + } + else if (strcmp(path, "-") == 0) + { + alloc = strdup(nsh_getwd(g_oldpwd)); + path = alloc; + } + else if (strcmp(path, "..") == 0) + { + alloc = strdup(nsh_getcwd()); + path = dirname(alloc); + } + else + { + fullpath = nsh_getfullpath(vtbl, path); + path = fullpath; + } + + /* Set the new workding directory */ + + ret = chdir(path); + if (ret != 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "chdir", NSH_ERRNO); + ret = ERROR; + } + + /* Free any memory that was allocated */ + + if (alloc) + { + free(alloc); + } + + if (fullpath) + { + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_echo + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_ECHO +int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + int i; + + /* echo each argument, separated by a space as it must have been on the + * command line + */ + + for (i = 1; i < argc; i++) + { + nsh_output(vtbl, "%s ", argv[i]); + } + nsh_output(vtbl, "\n"); + return OK; +} +#endif + +/**************************************************************************** + * Name: cmd_pwd + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +#ifndef CONFIG_NSH_DISABLE_PWD +int cmd_pwd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + nsh_output(vtbl, "%s\n", nsh_getcwd()); + return OK; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_set + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_ENVIRON +#ifndef CONFIG_NSH_DISABLE_SET +int cmd_set(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + int ret = setenv(argv[1], argv[2], TRUE); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "setenv", NSH_ERRNO); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_unset + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_ENVIRON +#ifndef CONFIG_NSH_DISABLE_UNSET +int cmd_unset(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + int ret = unsetenv(argv[1]); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "unsetenv", NSH_ERRNO); + } + return ret; +} +#endif +#endif diff --git a/apps/nshlib/nsh_fscmds.c b/apps/nshlib/nsh_fscmds.c new file mode 100644 index 000000000..f0451ce02 --- /dev/null +++ b/apps/nshlib/nsh_fscmds.c @@ -0,0 +1,1341 @@ +/**************************************************************************** + * apps/nshlib/nsh_fscmds.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# include <sys/stat.h> +# include <fcntl.h> +# if !defined(CONFIG_DISABLE_MOUNTPOINT) +# ifdef CONFIG_FS_READABLE /* Need at least one filesytem in configuration */ +# include <sys/mount.h> +# include <nuttx/ramdisk.h> +# endif +# ifdef CONFIG_FS_FAT +# include <nuttx/mkfatfs.h> +# endif +#endif +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <dirent.h> +#include <limits.h> +#include <libgen.h> +#include <errno.h> +#include <debug.h> + +#include "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define LSFLAGS_SIZE 1 +#define LSFLAGS_LONG 2 +#define LSFLAGS_RECURSIVE 4 + +/* The size of the I/O buffer may be specified in the + * configs/<board-name>defconfig file -- provided that it is at least as + * large as PATH_MAX. + */ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# ifdef CONFIG_NSH_FILEIOSIZE +# if CONFIG_NSH_FILEIOSIZE > (PATH_MAX + 1) +# define IOBUFFERSIZE CONFIG_NSH_FILEIOSIZE +# else +# define IOBUFFERSIZE (PATH_MAX + 1) +# endif +# else +# define IOBUFFERSIZE 1024 +# endif +# else +# define IOBUFFERSIZE (PATH_MAX + 1) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef int (*direntry_handler_t)(FAR struct nsh_vtbl_s *, const char *, struct dirent *, void *); + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Common buffer for file I/O. Note the use of this common buffer precludes + * multiple copies of NSH running concurrently. It should be allocated per + * NSH instance and retained in the "vtbl" as is done for the telnet + * connection. + */ + +static char g_iobuffer[IOBUFFERSIZE]; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: trim_dir + ****************************************************************************/ + +static void trim_dir(char *arg) +{ + /* Skip any trailing '/' characters (unless it is also the leading '/') */ + + int len = strlen(arg) - 1; + while (len > 0 && arg[len] == '/') + { + arg[len] = '\0'; + len--; + } +} + +/**************************************************************************** + * Name: nsh_getdirpath + ****************************************************************************/ + +static char *nsh_getdirpath(const char *path, const char *file) +{ + /* Handle the case where all that is left is '/' */ + + if (strcmp(path, "/") == 0) + { + sprintf(g_iobuffer, "/%s", file); + } + else + { + sprintf(g_iobuffer, "%s/%s", path, file); + } + + g_iobuffer[PATH_MAX] = '\0'; + return strdup(g_iobuffer); +} + +/**************************************************************************** + * Name: foreach_direntry + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +static int foreach_direntry(FAR struct nsh_vtbl_s *vtbl, const char *cmd, const char *dirpath, + direntry_handler_t handler, void *pvarg) +{ + DIR *dirp; + int ret = OK; + + /* Trim trailing '/' from directory names */ + +#ifdef CONFIG_NSH_FULLPATH + trim_dir(arg); +#endif + + /* Open the directory */ + + dirp = opendir(dirpath); + + if (!dirp) + { + /* Failed to open the directory */ + + nsh_output(vtbl, g_fmtnosuch, cmd, "directory", dirpath); + return ERROR; + } + + /* Read each directory entry */ + + for (;;) + { + struct dirent *entryp = readdir(dirp); + if (!entryp) + { + /* Finished with this directory */ + + break; + } + + /* Call the handler with this directory entry */ + + if (handler(vtbl, dirpath, entryp, pvarg) < 0) + { + /* The handler reported a problem */ + + ret = ERROR; + break; + } + } + + closedir(dirp); + return ret; +} +#endif + +/**************************************************************************** + * Name: ls_specialdir + ****************************************************************************/ + +static inline int ls_specialdir(const char *dir) +{ + /* '.' and '..' directories are not listed like normal directories */ + + return (strcmp(dir, ".") == 0 || strcmp(dir, "..") == 0); +} + +/**************************************************************************** + * Name: ls_handler + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +static int ls_handler(FAR struct nsh_vtbl_s *vtbl, const char *dirpath, struct dirent *entryp, void *pvarg) +{ + unsigned int lsflags = (unsigned int)pvarg; + int ret; + + /* Check if any options will require that we stat the file */ + + if ((lsflags & (LSFLAGS_SIZE|LSFLAGS_LONG)) != 0) + { + struct stat buf; + char *fullpath = nsh_getdirpath(dirpath, entryp->d_name); + + /* Yes, stat the file */ + + ret = stat(fullpath, &buf); + free(fullpath); + if (ret != 0) + { + nsh_output(vtbl, g_fmtcmdfailed, "ls", "stat", NSH_ERRNO); + return ERROR; + } + + if ((lsflags & LSFLAGS_LONG) != 0) + { + char details[] = "----------"; + if (S_ISDIR(buf.st_mode)) + { + details[0]='d'; + } + else if (S_ISCHR(buf.st_mode)) + { + details[0]='c'; + } + else if (S_ISBLK(buf.st_mode)) + { + details[0]='b'; + } + + if ((buf.st_mode & S_IRUSR) != 0) + { + details[1]='r'; + } + + if ((buf.st_mode & S_IWUSR) != 0) + { + details[2]='w'; + } + + if ((buf.st_mode & S_IXUSR) != 0) + { + details[3]='x'; + } + + if ((buf.st_mode & S_IRGRP) != 0) + { + details[4]='r'; + } + + if ((buf.st_mode & S_IWGRP) != 0) + { + details[5]='w'; + } + + if ((buf.st_mode & S_IXGRP) != 0) + { + details[6]='x'; + } + + if ((buf.st_mode & S_IROTH) != 0) + { + details[7]='r'; + } + + if ((buf.st_mode & S_IWOTH) != 0) + { + details[8]='w'; + } + + if ((buf.st_mode & S_IXOTH) != 0) + { + details[9]='x'; + } + + nsh_output(vtbl, " %s", details); + } + + if ((lsflags & LSFLAGS_SIZE) != 0) + { + nsh_output(vtbl, "%8d", buf.st_size); + } + } + + /* then provide the filename that is common to normal and verbose output */ + +#ifdef CONFIG_NSH_FULLPATH + nsh_output(vtbl, " %s/%s", arg, entryp->d_name); +#else + nsh_output(vtbl, " %s", entryp->d_name); +#endif + + if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name)) + { + nsh_output(vtbl, "/\n"); + } + else + { + nsh_output(vtbl, "\n"); + } + return OK; +} +#endif + +/**************************************************************************** + * Name: ls_recursive + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +static int ls_recursive(FAR struct nsh_vtbl_s *vtbl, const char *dirpath, + struct dirent *entryp, void *pvarg) +{ + int ret = OK; + + /* Is this entry a directory (and not one of the special directories, . and ..)? */ + + if (DIRENT_ISDIRECTORY(entryp->d_type) && !ls_specialdir(entryp->d_name)) + { + /* Yes.. */ + + char *newpath; + newpath = nsh_getdirpath(dirpath, entryp->d_name); + + /* List the directory contents */ + + nsh_output(vtbl, "%s:\n", newpath); + + /* Traverse the directory */ + + ret = foreach_direntry(vtbl, "ls", newpath, ls_handler, pvarg); + if (ret == 0) + { + /* Then recurse to list each directory within the directory */ + + ret = foreach_direntry(vtbl, "ls", newpath, ls_recursive, pvarg); + free(newpath); + } + } + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_cat + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_CAT +int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char buffer[IOBUFFERSIZE]; + char *fullpath; + int fd; + int i; + int ret = OK; + + /* Loop for each file name on the command line */ + + for (i = 1; i < argc && ret == OK; i++) + { + /* Get the fullpath to the file */ + + fullpath = nsh_getfullpath(vtbl, argv[i]); + if (fullpath) + { + /* Open the file for reading */ + + fd = open(fullpath, O_RDONLY); + if (fd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); + } + else + { + /* And just dump it byte for byte into stdout */ + + for (;;) + { + int nbytesread = read(fd, buffer, IOBUFFERSIZE); + + /* Check for read errors */ + + if (nbytesread < 0) + { + /* EINTR is not an error (but will stop stop the cat) */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (errno == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, argv[0]); + } + else +#endif + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO); + } + + ret = ERROR; + break; + } + + /* Check for data successfully read */ + + else if (nbytesread > 0) + { + int nbyteswritten = 0; + + while (nbyteswritten < nbytesread) + { + ssize_t n = nsh_write(vtbl, buffer, nbytesread); + if (n < 0) + { + /* EINTR is not an error (but will stop stop the cat) */ + + #ifndef CONFIG_DISABLE_SIGNALS + if (errno == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, argv[0]); + } + else +#endif + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO); + } + ret = ERROR; + break; + } + else + { + nbyteswritten += n; + } + } + } + + /* Otherwise, it is the end of file */ + + else + { + break; + } + } + + (void)close(fd); + } + + /* Free the allocated full path */ + + nsh_freefullpath(fullpath); + } + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_cp + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_CP +int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct stat buf; + char *srcpath = NULL; + char *destpath = NULL; + char *allocpath = NULL; + int oflags = O_WRONLY|O_CREAT|O_TRUNC; + int rdfd; + int wrfd; + int ret = ERROR; + + /* Get the full path to the source file */ + + srcpath = nsh_getfullpath(vtbl, argv[1]); + if (!srcpath) + { + goto errout; + } + + /* Open the source file for reading */ + + rdfd = open(srcpath, O_RDONLY); + if (rdfd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); + goto errout_with_srcpath; + } + + /* Get the full path to the destination file or directory */ + + destpath = nsh_getfullpath(vtbl, argv[2]); + if (!destpath) + { + goto errout_with_rdfd; + } + + /* Check if the destination is a directory */ + + ret = stat(destpath, &buf); + if (ret == 0) + { + /* Something exists here... is it a directory? */ + + if (S_ISDIR(buf.st_mode)) + { + /* Yes, it is a directory. Remove any trailing '/' characters from the path */ + + trim_dir(argv[2]); + + /* Construct the full path to the new file */ + + allocpath = nsh_getdirpath(argv[2], basename(argv[1]) ); + if (!allocpath) + { + nsh_output(vtbl, g_fmtcmdoutofmemory, argv[0]); + goto errout_with_destpath; + } + + /* Open then dest for writing */ + + nsh_freefullpath(destpath); + destpath = allocpath; + } + else if (!S_ISREG(buf.st_mode)) + { + /* Maybe it is a driver? */ + + oflags = O_WRONLY; + } + } + + /* Now open the destination */ + + wrfd = open(destpath, oflags, 0666); + if (wrfd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); + goto errout_with_allocpath; + } + + /* Now copy the file */ + + for (;;) + { + int nbytesread; + int nbyteswritten; + + do + { + nbytesread = read(rdfd, g_iobuffer, IOBUFFERSIZE); + if (nbytesread == 0) + { + /* End of file */ + + ret = OK; + goto errout_with_wrfd; + } + else if (nbytesread < 0) + { + /* EINTR is not an error (but will still stop the copy) */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (errno == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, argv[0]); + } + else +#endif + { + /* Read error */ + + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "read", NSH_ERRNO); + } + goto errout_with_wrfd; + } + } + while (nbytesread <= 0); + + do + { + nbyteswritten = write(wrfd, g_iobuffer, nbytesread); + if (nbyteswritten >= 0) + { + nbytesread -= nbyteswritten; + } + else + { + /* EINTR is not an error (but will still stop the copy) */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (errno == EINTR) + { + nsh_output(vtbl, g_fmtsignalrecvd, argv[0]); + } + else +#endif + { + /* Read error */ + + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "write", NSH_ERRNO); + } + goto errout_with_wrfd; + } + } + while (nbytesread > 0); + } + +errout_with_wrfd: + close(wrfd); + +errout_with_allocpath: + if (allocpath) + { + free(allocpath); + } + +errout_with_destpath: + if (destpath && !allocpath) + { + nsh_freefullpath(destpath); + } + +errout_with_rdfd: + close(rdfd); + +errout_with_srcpath: + if (srcpath) + { + nsh_freefullpath(srcpath); + } +errout: + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_losetup + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) +#ifndef CONFIG_NSH_DISABLE_LOSETUP +int cmd_losetup(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *loopdev = NULL; + char *filepath = NULL; + bool teardown = false; + bool readonly = false; + off_t offset = 0; + bool badarg = false; + int ret = ERROR; + int option; + + /* Get the losetup options: Two forms are supported: + * + * losetup -d <loop-device> + * losetup [-o <offset>] [-r] <loop-device> <filename> + * + * NOTE that the -o and -r options are accepted with the -d option, but + * will be ignored. + */ + + while ((option = getopt(argc, argv, "d:o:r")) != ERROR) + { + switch (option) + { + case 'd': + loopdev = nsh_getfullpath(vtbl, optarg); + teardown = true; + break; + + case 'o': + offset = atoi(optarg); + break; + + case 'r': + readonly = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + goto errout_with_paths; + } + + /* If this is not a tear down operation, then additional command line + * parameters are required. + */ + + if (!teardown) + { + /* There must be two arguments on the command line after the options */ + + if (optind + 1 < argc) + { + loopdev = nsh_getfullpath(vtbl, argv[optind]); + optind++; + + filepath = nsh_getfullpath(vtbl, argv[optind]); + optind++; + } + else + { + nsh_output(vtbl, g_fmtargrequired, argv[0]); + goto errout_with_paths; + } + } + + /* There should be nothing else on the command line */ + + if (optind < argc) + { + nsh_output(vtbl, g_fmttoomanyargs, argv[0]); + goto errout_with_paths; + } + + /* Perform the teardown operation */ + + if (teardown) + { + /* Tear down the loop device. */ + + ret = loteardown(loopdev); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "loteardown", NSH_ERRNO_OF(-ret)); + goto errout_with_paths; + } + } + else + { + /* Set up the loop device */ + + ret = losetup(loopdev, filepath, 512, offset, readonly); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "losetup", NSH_ERRNO_OF(-ret)); + goto errout_with_paths; + } + } + + /* Free memory */ + +errout_with_paths: + if (loopdev) + { + free(loopdev); + } + + if (filepath) + { + free(filepath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_ls + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_LS +int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + const char *relpath; + unsigned int lsflags = 0; + char *fullpath; + bool badarg = false; + int ret; + + /* Get the ls options */ + + int option; + while ((option = getopt(argc, argv, "lRs")) != ERROR) + { + switch (option) + { + case 'l': + lsflags |= (LSFLAGS_SIZE|LSFLAGS_LONG); + break; + + case 'R': + lsflags |= LSFLAGS_RECURSIVE; + break; + + case 's': + lsflags |= LSFLAGS_SIZE; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + return ERROR; + } + + /* There may be one argument after the options */ + + if (optind + 1 < argc) + { + nsh_output(vtbl, g_fmttoomanyargs, argv[0]); + return ERROR; + } + else if (optind >= argc) + { +#ifndef CONFIG_DISABLE_ENVIRON + relpath = nsh_getcwd(); +#else + nsh_output(vtbl, g_fmtargrequired, argv[0]); + return ERROR; +#endif + } + else + { + relpath = argv[optind]; + } + + /* Get the fullpath to the directory */ + + fullpath = nsh_getfullpath(vtbl, relpath); + if (!fullpath) + { + return ERROR; + } + + /* List the directory contents */ + + nsh_output(vtbl, "%s:\n", fullpath); + ret = foreach_direntry(vtbl, "ls", fullpath, ls_handler, (void*)lsflags); + if (ret == OK && (lsflags & LSFLAGS_RECURSIVE) != 0) + { + /* Then recurse to list each directory within the directory */ + + ret = foreach_direntry(vtbl, "ls", fullpath, ls_recursive, (void*)lsflags); + } + nsh_freefullpath(fullpath); + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mkdir + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_NSH_DISABLE_MKDIR +int cmd_mkdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = mkdir(fullpath, 0777); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkdir", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mkfatfs + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_FAT) +#ifndef CONFIG_NSH_DISABLE_MKFATFS +int cmd_mkfatfs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct fat_format_s fmt = FAT_FORMAT_INITIALIZER; + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = mkfatfs(fullpath, &fmt); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfatfs", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mkfifo + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_MKFIFO +int cmd_mkfifo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = mkfifo(fullpath, 0777); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mkfifo", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mkrd + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_NSH_DISABLE_MKRD +int cmd_mkrd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + const char *fmt; + uint8_t *buffer; + uint32_t nsectors; + bool badarg = false; + int sectsize = 512; + int minor = 0; + int ret; + + /* Get the mount options */ + + int option; + while ((option = getopt(argc, argv, ":m:s:")) != ERROR) + { + switch (option) + { + case 'm': + minor = atoi(optarg); + if (minor < 0 || minor > 255) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + badarg = true; + } + break; + + case 's': + sectsize = atoi(optarg); + if (minor < 0 || minor > 16384) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + badarg = true; + } + break; + + case ':': + nsh_output(vtbl, g_fmtargrequired, argv[0]); + badarg = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + return ERROR; + } + + /* There should be exactly on parameter left on the command-line */ + + if (optind == argc-1) + { + nsectors = (uint32_t)atoi(argv[optind]); + } + else if (optind >= argc) + { + fmt = g_fmttoomanyargs; + goto errout_with_fmt; + } + else + { + fmt = g_fmtargrequired; + goto errout_with_fmt; + } + + /* Allocate the memory backing up the ramdisk */ + + buffer = (uint8_t*)malloc(sectsize * nsectors); + if (!buffer) + { + fmt = g_fmtcmdoutofmemory; + goto errout_with_fmt; + } + +#ifdef CONFIG_DEBUG_VERBOSE + memset(buffer, 0, sectsize * nsectors); +#endif + dbg("RAMDISK at %p\n", buffer); + + /* Then register the ramdisk */ + + ret = ramdisk_register(minor, buffer, nsectors, sectsize, true); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "ramdisk_register", NSH_ERRNO_OF(-ret)); + free(buffer); + return ERROR; + } + return ret; + +errout_with_fmt: + nsh_output(vtbl, fmt, argv[0]); + return ERROR; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_mount + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE) +#ifndef CONFIG_NSH_DISABLE_MOUNT +int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *source; + char *target; + char *filesystem = 0; + bool badarg = false; + int ret; + + /* Get the mount options */ + + int option; + while ((option = getopt(argc, argv, ":t:")) != ERROR) + { + switch (option) + { + case 't': + filesystem = optarg; + break; + + case ':': + nsh_output(vtbl, g_fmtargrequired, argv[0]); + badarg = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + return ERROR; + } + + /* There are two required arguments after the options */ + + if (optind + 2 < argc) + { + nsh_output(vtbl, g_fmttoomanyargs, argv[0]); + return ERROR; + } + else if (optind + 2 > argc) + { + nsh_output(vtbl, g_fmtargrequired, argv[0]); + return ERROR; + } + + /* The source and target pathes might be relative to the current + * working directory. + */ + + source = nsh_getfullpath(vtbl, argv[optind]); + if (!source) + { + return ERROR; + } + + target = nsh_getfullpath(vtbl, argv[optind+1]); + if (!source) + { + nsh_freefullpath(source); + return ERROR; + } + + /* Perform the mount */ + + ret = mount(source, target, filesystem, 0, NULL); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mount", NSH_ERRNO); + } + + nsh_freefullpath(source); + nsh_freefullpath(target); + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_rm + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_NSH_DISABLE_RM +int cmd_rm(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = unlink(fullpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "unlink", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_rmdir + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +#ifndef CONFIG_NSH_DISABLE_RMDIR +int cmd_rmdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + ret = rmdir(fullpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "rmdir", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif + +/**************************************************************************** + * Name: nsh_script + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) +int nsh_script(FAR struct nsh_vtbl_s *vtbl, const char *cmd, const char *path) +{ + char *fullpath; + FILE *stream; + char *buffer; + char *pret; + int ret = ERROR; + + /* The path to the script may be relative to the current working directory */ + + fullpath = nsh_getfullpath(vtbl, path); + if (!fullpath) + { + return ERROR; + } + + /* Get a reference to the common input buffer */ + + buffer = nsh_linebuffer(vtbl); + if (buffer) + { + /* Open the file containing the script */ + + stream = fopen(fullpath, "r"); + if (!stream) + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "fopen", NSH_ERRNO); + nsh_freefullpath(fullpath); + return ERROR; + } + + /* Loop, processing each command line in the script file (or + * until an error occurs) + */ + + do + { + /* Get the next line of input from the file*/ + + fflush(stdout); + pret = fgets(buffer, CONFIG_NSH_LINELEN, stream); + if (pret) + { + /* Parse process the command. NOTE: this is recursive... + * we got to cmd_sh via a call to nsh_parse. So some + * considerable amount of stack may be used. + */ + + ret = nsh_parse(vtbl, buffer); + } + } + while (pret && ret == OK); + fclose(stream); + } + + nsh_freefullpath(fullpath); + return ret; +} +#endif + +/**************************************************************************** + * Name: cmd_sh + ****************************************************************************/ + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) +#ifndef CONFIG_NSH_DISABLE_SH +int cmd_sh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + return nsh_script(vtbl, argv[0], argv[1]); +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_umount + ****************************************************************************/ + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE) +#ifndef CONFIG_NSH_DISABLE_UMOUNT +int cmd_umount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *fullpath = nsh_getfullpath(vtbl, argv[1]); + int ret = ERROR; + + if (fullpath) + { + /* Perform the umount */ + + ret = umount(fullpath); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "umount", NSH_ERRNO); + } + nsh_freefullpath(fullpath); + } + return ret; +} +#endif +#endif diff --git a/apps/nshlib/nsh_mmcmds.c b/apps/nshlib/nsh_mmcmds.c new file mode 100644 index 000000000..4b6e0bf41 --- /dev/null +++ b/apps/nshlib/nsh_mmcmds.c @@ -0,0 +1,95 @@ +/**************************************************************************** + * apps/nshlib/dbg_mmcmds.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> + +#include "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_free + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_FREE +int cmd_free(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct mallinfo mem; + +#ifdef CONFIG_CAN_PASS_STRUCTS + mem = mallinfo(); +#else + (void)mallinfo(&mem); +#endif + + nsh_output(vtbl, " total used free largest\n"); + nsh_output(vtbl, "Mem: %11d%11d%11d%11d\n", + mem.arena, mem.uordblks, mem.fordblks, mem.mxordblk); + + return OK; +} +#endif diff --git a/apps/nshlib/nsh_netcmds.c b/apps/nshlib/nsh_netcmds.c new file mode 100644 index 000000000..8285da295 --- /dev/null +++ b/apps/nshlib/nsh_netcmds.c @@ -0,0 +1,863 @@ +/**************************************************************************** + * apps/nshlib/nsh_netcmds.c + * + * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#ifdef CONFIG_NET + +#include <sys/stat.h> /* Needed for open */ +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sched.h> +#include <fcntl.h> /* Needed for open */ +#include <libgen.h> /* Needed for basename */ +#include <errno.h> + +#include <nuttx/net.h> +#include <nuttx/clock.h> +#include <net/ethernet.h> +#include <net/uip/uip.h> +#include <net/uip/uip-arch.h> +#include <netinet/ether.h> + +#ifdef CONFIG_NET_STATISTICS +# include <net/uip/uip.h> +#endif + +#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ + !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS) +# include <apps/netutils/uiplib.h> +#endif + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +# include <apps/netutils/uiplib.h> +# include <apps/netutils/tftp.h> +#endif + +#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_WGET +# include <apps/netutils/uiplib.h> +# include <apps/netutils/webclient.h> +# endif +#endif + +#include "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define DEFAULT_PING_DATALEN 56 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +struct tftpc_args_s +{ + bool binary; /* true:binary ("octect") false:text ("netascii") */ + bool allocated; /* true: destpath is allocated */ + char *destpath; /* Path at destination */ + const char *srcpath; /* Path at src */ + in_addr_t ipaddr; /* Host IP address */ +}; +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ + !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS) +static uint16_t g_pingid = 0; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ping_newid + ****************************************************************************/ + +#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ + !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS) +static inline uint16_t ping_newid(void) +{ + irqstate_t save = irqsave(); + uint16_t ret = ++g_pingid; + irqrestore(save); + return ret; +} +#endif + +/**************************************************************************** + * Name: uip_statistics + ****************************************************************************/ + +#if defined(CONFIG_NET_STATISTICS) && !defined(CONFIG_NSH_DISABLE_IFCONFIG) +static inline void uip_statistics(FAR struct nsh_vtbl_s *vtbl) +{ + nsh_output(vtbl, "uIP IP "); +#ifdef CONFIG_NET_TCP + nsh_output(vtbl, " TCP"); +#endif +#ifdef CONFIG_NET_UDP + nsh_output(vtbl, " UDP"); +#endif +#ifdef CONFIG_NET_ICMP + nsh_output(vtbl, " ICMP"); +#endif + nsh_output(vtbl, "\n"); + + /* Received packets */ + + nsh_output(vtbl, "Received %04x",uip_stat.ip.recv); +#ifdef CONFIG_NET_TCP + nsh_output(vtbl, " %04x",uip_stat.tcp.recv); +#endif +#ifdef CONFIG_NET_UDP + nsh_output(vtbl, " %04x",uip_stat.udp.recv); +#endif +#ifdef CONFIG_NET_ICMP + nsh_output(vtbl, " %04x",uip_stat.icmp.recv); +#endif + nsh_output(vtbl, "\n"); + + /* Dropped packets */ + + nsh_output(vtbl, "Dropped %04x",uip_stat.ip.drop); +#ifdef CONFIG_NET_TCP + nsh_output(vtbl, " %04x",uip_stat.tcp.drop); +#endif +#ifdef CONFIG_NET_UDP + nsh_output(vtbl, " %04x",uip_stat.udp.drop); +#endif +#ifdef CONFIG_NET_ICMP + nsh_output(vtbl, " %04x",uip_stat.icmp.drop); +#endif + nsh_output(vtbl, "\n"); + + nsh_output(vtbl, " IP VHL: %04x HBL: %04x\n", + uip_stat.ip.vhlerr, uip_stat.ip.hblenerr); + nsh_output(vtbl, " LBL: %04x Frg: %04x\n", + uip_stat.ip.lblenerr, uip_stat.ip.fragerr); + + nsh_output(vtbl, " Checksum %04x",uip_stat.ip.chkerr); +#ifdef CONFIG_NET_TCP + nsh_output(vtbl, " %04x",uip_stat.tcp.chkerr); +#endif +#ifdef CONFIG_NET_UDP + nsh_output(vtbl, " %04x",uip_stat.udp.chkerr); +#endif +#ifdef CONFIG_NET_ICMP + nsh_output(vtbl, " ----"); +#endif + nsh_output(vtbl, "\n"); + +#ifdef CONFIG_NET_TCP + nsh_output(vtbl, " TCP ACK: %04x SYN: %04x\n", + uip_stat.tcp.ackerr, uip_stat.tcp.syndrop); + nsh_output(vtbl, " RST: %04x %04x\n", + uip_stat.tcp.rst, uip_stat.tcp.synrst); +#endif + + nsh_output(vtbl, " Type %04x",uip_stat.ip.protoerr); +#ifdef CONFIG_NET_TCP + nsh_output(vtbl, " ----"); +#endif +#ifdef CONFIG_NET_UDP + nsh_output(vtbl, " ----"); +#endif +#ifdef CONFIG_NET_ICMP + nsh_output(vtbl, " %04x",uip_stat.icmp.typeerr); +#endif + nsh_output(vtbl, "\n"); + + /* Sent packets */ + + nsh_output(vtbl, "Sent ----",uip_stat.ip.sent); +#ifdef CONFIG_NET_TCP + nsh_output(vtbl, " %04x",uip_stat.tcp.sent); +#endif +#ifdef CONFIG_NET_UDP + nsh_output(vtbl, " %04x",uip_stat.udp.sent); +#endif +#ifdef CONFIG_NET_ICMP + nsh_output(vtbl, " %04x",uip_stat.icmp.sent); +#endif + nsh_output(vtbl, "\n"); + +#ifdef CONFIG_NET_TCP + nsh_output(vtbl, " Rexmit ---- %04x",uip_stat.tcp.rexmit); +#ifdef CONFIG_NET_UDP + nsh_output(vtbl, " ----"); +#endif +#ifdef CONFIG_NET_ICMP + nsh_output(vtbl, " ----"); +#endif + nsh_output(vtbl, "\n"); +#endif + nsh_output(vtbl, "\n"); +} +#else +# define uip_statistics(vtbl) +#endif + + +/**************************************************************************** + * Name: ifconfig_callback + ****************************************************************************/ + +int ifconfig_callback(FAR struct uip_driver_s *dev, void *arg) +{ + struct nsh_vtbl_s *vtbl = (struct nsh_vtbl_s*)arg; + struct in_addr addr; + + nsh_output(vtbl, "%s\tHWaddr %s\n", dev->d_ifname, ether_ntoa(&dev->d_mac)); + addr.s_addr = dev->d_ipaddr; + nsh_output(vtbl, "\tIPaddr:%s ", inet_ntoa(addr)); + addr.s_addr = dev->d_draddr; + nsh_output(vtbl, "DRaddr:%s ", inet_ntoa(addr)); + addr.s_addr = dev->d_netmask; + nsh_output(vtbl, "Mask:%s\n\n", inet_ntoa(addr)); + return OK; +} + +/**************************************************************************** + * Name: tftpc_parseargs + ****************************************************************************/ + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +int tftpc_parseargs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv, + struct tftpc_args_s *args) +{ + FAR const char *fmt = g_fmtarginvalid; + bool badarg = false; + int option; + + /* Get the ping options */ + + memset(args, 0, sizeof(struct tftpc_args_s)); + while ((option = getopt(argc, argv, ":bnf:h:")) != ERROR) + { + switch (option) + { + case 'b': + args->binary = true; + break; + + case 'n': + args->binary = false; + break; + + case 'f': + args->destpath = optarg; + break; + + case 'h': + if (!uiplib_ipaddrconv(optarg, (FAR unsigned char*)&args->ipaddr)) + { + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + } + break; + + case ':': + nsh_output(vtbl, g_fmtargrequired, argv[0]); + badarg = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + return ERROR; + } + + /* There should be exactly one parameter left on the command-line */ + + if (optind == argc-1) + { + args->srcpath = argv[optind]; + } + + /* optind == argc means that there is nothing left on the command-line */ + + else if (optind >= argc) + { + fmt = g_fmtargrequired; + goto errout; + } + + /* optind < argc-1 means that there are too many arguments on the + * command-line + */ + + else + { + fmt = g_fmttoomanyargs; + goto errout; + } + + /* The HOST IP address is also required */ + + if (!args->ipaddr) + { + fmt = g_fmtargrequired; + goto errout; + } + + /* If the destpath was not provided, then we have do a little work. */ + + if (!args->destpath) + { + char *tmp1; + char *tmp2; + + /* Copy the srcpath... baseanme might modify it */ + + fmt = g_fmtcmdoutofmemory; + tmp1 = strdup(args->srcpath); + if (!tmp1) + { + goto errout; + } + + /* Get the basename of the srcpath */ + + tmp2 = basename(tmp1); + if (!tmp2) + { + free(tmp1); + goto errout; + } + + /* Use that basename as the destpath */ + + args->destpath = strdup(tmp2); + free(tmp1); + if (!args->destpath) + { + goto errout; + } + args->allocated = true; + } + + return OK; + +errout: + nsh_output(vtbl, fmt, argv[0]); + return ERROR; +} +#endif + +/**************************************************************************** + * Name: wget_callback + ****************************************************************************/ + +#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_WGET +static void wget_callback(FAR char **buffer, int offset, int datend, + FAR int *buflen, FAR void *arg) +{ + (void)write((int)arg, &((*buffer)[offset]), datend - offset); +} +#endif +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_get + ****************************************************************************/ + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_GET +int cmd_get(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct tftpc_args_s args; + char *fullpath; + + /* Parse the input parameter list */ + + if (tftpc_parseargs(vtbl, argc, argv, &args) != OK) + { + return ERROR; + } + + /* Get the full path to the local file */ + + fullpath = nsh_getfullpath(vtbl, args.srcpath); + + /* Then perform the TFTP get operation */ + + if (tftpget(args.srcpath, fullpath, args.ipaddr, args.binary) != OK) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "tftpget", NSH_ERRNO); + } + + /* Release any allocated memory */ + + if (args.allocated) + { + free(args.destpath); + } + free(fullpath); + return OK; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_ifconfig + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_IFCONFIG +int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct in_addr addr; + in_addr_t ip; + + /* With one or no arguments, ifconfig simply shows the status of ethernet + * device: + * + * ifconfig + * ifconfig [nic_name] + */ + + if (argc <= 2) + { + netdev_foreach(ifconfig_callback, vtbl); + uip_statistics(vtbl); + return OK; + } + + /* If both the network interface name and an IP address are supplied as + * arguments, then ifconfig will set the address of the ethernet device: + * + * ifconfig nic_name ip_address + */ + + /* Set host ip address */ + + ip = addr.s_addr = inet_addr(argv[2]); + uip_sethostaddr(argv[1], &addr); + + /* Set gateway */ + + ip = NTOHL(ip); + ip &= ~0x000000ff; + ip |= 0x00000001; + + addr.s_addr = HTONL(ip); + uip_setdraddr(argv[1], &addr); + + /* Set netmask */ + + addr.s_addr = inet_addr("255.255.255.0"); + uip_setnetmask(argv[1], &addr); + + return OK; +} +#endif + +/**************************************************************************** + * Name: cmd_ping + ****************************************************************************/ + +#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ + !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS) +#ifndef CONFIG_NSH_DISABLE_PING +int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + FAR const char *fmt = g_fmtarginvalid; + const char *staddr; + uip_ipaddr_t ipaddr; + uint32_t start; + uint32_t next; + uint32_t dsec = 10; + uint16_t id; + bool badarg = false; + int count = 10; + int option; + int seqno; + int replies = 0; + int elapsed; + int tmp; + int i; + + /* Get the ping options */ + + while ((option = getopt(argc, argv, ":c:i:")) != ERROR) + { + switch (option) + { + case 'c': + count = atoi(optarg); + if (count < 1 || count > 10000) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + badarg = true; + } + break; + + case 'i': + tmp = atoi(optarg); + if (tmp < 1 || tmp >= 4294) + { + nsh_output(vtbl, g_fmtargrange, argv[0]); + badarg = true; + } + else + { + dsec = 10 * tmp; + } + break; + + case ':': + nsh_output(vtbl, g_fmtargrequired, argv[0]); + badarg = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + return ERROR; + } + + /* There should be exactly on parameter left on the command-line */ + + if (optind == argc-1) + { + staddr = argv[optind]; + if (!uiplib_ipaddrconv(staddr, (FAR unsigned char*)&ipaddr)) + { + goto errout; + } + } + else if (optind >= argc) + { + fmt = g_fmttoomanyargs; + goto errout; + } + else + { + fmt = g_fmtargrequired; + goto errout; + } + + /* Get the ID to use */ + + id = ping_newid(); + + /* Loop for the specified count */ + + nsh_output(vtbl, "PING %s %d bytes of data\n", staddr, DEFAULT_PING_DATALEN); + start = g_system_timer; + for (i = 1; i <= count; i++) + { + /* Send the ECHO request and wait for the response */ + + next = g_system_timer; + seqno = uip_ping(ipaddr, id, i, DEFAULT_PING_DATALEN, dsec); + + /* Was any response returned? We can tell if a non-negative sequence + * number was returned. + */ + + if (seqno >= 0 && seqno <= i) + { + /* Get the elpased time from the time that the request was + * sent until the response was received. If we got a response + * to an earlier request, then fudge the elpased time. + */ + + elapsed = TICK2MSEC(g_system_timer - next); + if (seqno < i) + { + elapsed += 100*dsec*(i - seqno); + } + + /* Report the receipt of the reply */ + + nsh_output(vtbl, "%d bytes from %s: icmp_seq=%d time=%d ms\n", + DEFAULT_PING_DATALEN, staddr, seqno, elapsed); + replies++; + } + + /* Wait for the remainder of the interval. If the last seqno<i, + * then this is a bad idea... we will probably lose the response + * to the current request! + */ + + elapsed = TICK2DSEC(g_system_timer - next); + if (elapsed < dsec) + { + usleep(100000*dsec); + } + } + + /* Get the total elapsed time */ + + elapsed = TICK2MSEC(g_system_timer - start); + + /* Calculate the percentage of lost packets */ + + tmp = (100*(count - replies) + (count >> 1)) / count; + + nsh_output(vtbl, "%d packets transmitted, %d received, %d%% packet loss, time %d ms\n", + count, replies, tmp, elapsed); + return OK; + +errout: + nsh_output(vtbl, fmt, argv[0]); + return ERROR; +} +#endif +#endif /* CONFIG_NET_ICMP && CONFIG_NET_ICMP_PING */ + +/**************************************************************************** + * Name: cmd_put + ****************************************************************************/ + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_PUT +int cmd_put(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + struct tftpc_args_s args; + char *fullpath; + + /* Parse the input parameter list */ + + if (tftpc_parseargs(vtbl, argc, argv, &args) != OK) + { + return ERROR; + } + + /* Get the full path to the local file */ + + fullpath = nsh_getfullpath(vtbl, args.srcpath); + + /* Then perform the TFTP put operation */ + + if (tftpput(fullpath, args.destpath, args.ipaddr, args.binary) != OK) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "tftpput", NSH_ERRNO); + } + + /* Release any allocated memory */ + + if (args.allocated) + { + free(args.destpath); + } + free(fullpath); + return OK; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_wget + ****************************************************************************/ + +#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 +#ifndef CONFIG_NSH_DISABLE_WGET +int cmd_wget(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *localfile = NULL; + char *allocfile = NULL; + char *buffer = NULL; + char *fullpath = NULL; + char *url; + const char *fmt; + bool badarg = false; + int option; + int fd = -1; + int ret; + + /* Get the wget options */ + + while ((option = getopt(argc, argv, ":o:")) != ERROR) + { + switch (option) + { + case 'o': + localfile = optarg; + break; + + case ':': + nsh_output(vtbl, g_fmtargrequired, argv[0]); + badarg = true; + break; + + case '?': + default: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + badarg = true; + break; + } + } + + /* If a bad argument was encountered, then return without processing the command */ + + if (badarg) + { + return ERROR; + } + + /* There should be exactly on parameter left on the command-line */ + + if (optind == argc-1) + { + url = argv[optind]; + } + else if (optind >= argc) + { + fmt = g_fmttoomanyargs; + goto errout; + } + else + { + fmt = g_fmtargrequired; + goto errout; + } + + /* Get the local file name */ + + if (!localfile) + { + allocfile = strdup(url); + localfile = basename(allocfile); + } + + /* Get the full path to the local file */ + + fullpath = nsh_getfullpath(vtbl, localfile); + + /* Open the local file for writing */ + + fd = open(fullpath, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO); + ret = ERROR; + goto exit; + } + + /* Allocate an I/O buffer */ + + buffer = malloc(512); + if (!buffer) + { + fmt = g_fmtcmdoutofmemory; + goto errout; + } + + /* And perform the wget */ + + ret = wget(url, buffer, 512, wget_callback, (FAR void *)fd); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "wget", NSH_ERRNO); + goto exit; + } + + /* Free allocated resources */ + +exit: + if (fd >= 0) + { + close(fd); + } + if (allocfile) + { + free(allocfile); + } + if (fullpath) + { + free(fullpath); + } + if (buffer) + { + free(buffer); + } + return ret; + +errout: + nsh_output(vtbl, fmt, argv[0]); + ret = ERROR; + goto exit; +} +#endif +#endif + +#endif /* CONFIG_NET */ diff --git a/apps/nshlib/nsh_netinit.c b/apps/nshlib/nsh_netinit.c new file mode 100644 index 000000000..245d50380 --- /dev/null +++ b/apps/nshlib/nsh_netinit.c @@ -0,0 +1,170 @@ +/**************************************************************************** + * apps/nshlib/nsh_netinit.c + * + * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * This is influenced by similar logic from uIP: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <debug.h> + +#include <net/if.h> + +#include <apps/netutils/uiplib.h> +#if defined(CONFIG_NSH_DHCPC) +# include <apps/netutils/resolv.h> +# include <apps/netutils/dhcpc.h> +#endif + +#include "nsh.h" + +#ifdef CONFIG_NET + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_netinit + * + * Description: + * Initialize the network per the selected NuttX configuration + * + ****************************************************************************/ + +int nsh_netinit(void) +{ + struct in_addr addr; +#if defined(CONFIG_NSH_DHCPC) + FAR void *handle; +#endif +#if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_NOMAC) + uint8_t mac[IFHWADDRLEN]; +#endif + +/* Many embedded network interfaces must have a software assigned MAC */ + +#ifdef CONFIG_NSH_NOMAC + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0xb0; + mac[3] = 0x0b; + mac[4] = 0xba; + mac[5] = 0xbe; + uip_setmacaddr("eth0", mac); +#endif + + /* Set up our host address */ + +#if !defined(CONFIG_NSH_DHCPC) + addr.s_addr = HTONL(CONFIG_NSH_IPADDR); +#else + addr.s_addr = 0; +#endif + uip_sethostaddr("eth0", &addr); + + /* Set up the default router address */ + + addr.s_addr = HTONL(CONFIG_NSH_DRIPADDR); + uip_setdraddr("eth0", &addr); + + /* Setup the subnet mask */ + + addr.s_addr = HTONL(CONFIG_NSH_NETMASK); + uip_setnetmask("eth0", &addr); + +#if defined(CONFIG_NSH_DHCPC) + /* Set up the resolver */ + + resolv_init(); +#endif + +#if defined(CONFIG_NSH_DHCPC) + /* Get the MAC address of the NIC */ + + uip_getmacaddr("eth0", mac); + + /* Set up the DHCPC modules */ + + handle = dhcpc_open(&mac, IFHWADDRLEN); + + /* Get an IP address. Note that there is no logic for renewing the IP address in this + * example. The address should be renewed in ds.lease_time/2 seconds. + */ + + if (handle) + { + struct dhcpc_state ds; + (void)dhcpc_request(handle, &ds); + uip_sethostaddr("eth1", &ds.ipaddr); + if (ds.netmask.s_addr != 0) + { + uip_setnetmask("eth0", &ds.netmask); + } + if (ds.default_router.s_addr != 0) + { + uip_setdraddr("eth0", &ds.default_router); + } + if (ds.dnsaddr.s_addr != 0) + { + resolv_conf(&ds.dnsaddr); + } + dhcpc_close(handle); + } +#endif + return OK; +} + +#endif /* CONFIG_NET */ diff --git a/apps/nshlib/nsh_parse.c b/apps/nshlib/nsh_parse.c new file mode 100644 index 000000000..a193ebc9e --- /dev/null +++ b/apps/nshlib/nsh_parse.c @@ -0,0 +1,1336 @@ +/**************************************************************************** + * apps/nshlib/nsh_parse.c + * + * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/stat.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sched.h> +#include <fcntl.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/version.h> + +#ifndef CONFIG_NSH_DISABLEBG +# include <pthread.h> +#endif + +#ifdef CONFIG_NSH_BUILTIN_APPS +# include <apps/apps.h> +#endif +#include <apps/nsh.h> + +#include "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Argument list size + * + * argv[0]: The command name. + * argv[1]: The beginning of argument (up to NSH_MAX_ARGUMENTS) + * argv[argc-3]: Possibly '>' or '>>' + * argv[argc-2]: Possibly <file> + * argv[argc-1]: Possibly '&' (if pthreads are enabled) + * argv[argc]: NULL terminating pointer + * + * Maximum size is NSH_MAX_ARGUMENTS+5 + */ + +#ifndef CONFIG_NSH_DISABLEBG +# define MAX_ARGV_ENTRIES (NSH_MAX_ARGUMENTS+5) +#else +# define MAX_ARGV_ENTRIES (NSH_MAX_ARGUMENTS+4) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct cmdmap_s +{ + const char *cmd; /* Name of the command */ + cmd_t handler; /* Function that handles the command */ + uint8_t minargs; /* Minimum number of arguments (including command) */ + uint8_t maxargs; /* Maximum number of arguments (including command) */ + const char *usage; /* Usage instructions for 'help' command */ +}; + +#ifndef CONFIG_NSH_DISABLEBG +struct cmdarg_s +{ + FAR struct nsh_vtbl_s *vtbl; /* For front-end interaction */ + int fd; /* FD for output redirection */ + int argc; /* Number of arguments in argv */ + FAR char *argv[MAX_ARGV_ENTRIES]; /* Argument list */ +}; +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_HELP + static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif + +#ifndef CONFIG_NSH_DISABLE_EXIT + static int cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); +#endif +static int cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_delim[] = " \t\n"; +static const char g_redirect1[] = ">"; +static const char g_redirect2[] = ">>"; +static const char g_exitstatus[] = "$?"; +static const char g_success[] = "0"; +static const char g_failure[] = "1"; + +static const struct cmdmap_s g_cmdmap[] = +{ +#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_TEST) + { "[", cmd_lbracket, 4, NSH_MAX_ARGUMENTS, "<expression> ]" }, +#endif + +#ifndef CONFIG_NSH_DISABLE_HELP + { "?", cmd_help, 1, 1, NULL }, +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_CAT + { "cat", cmd_cat, 2, NSH_MAX_ARGUMENTS, "<path> [<path> [<path> ...]]" }, +# endif +#ifndef CONFIG_DISABLE_ENVIRON +# ifndef CONFIG_NSH_DISABLE_CD + { "cd", cmd_cd, 1, 2, "[<dir-path>|-|~|..]" }, +# endif +#endif +# ifndef CONFIG_NSH_DISABLE_CP + { "cp", cmd_cp, 3, 3, "<source-path> <dest-path>" }, +# endif +#endif + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) + { "date", cmd_date, 1, 3, "[-s \"MMM DD HH:MM:SS YYYY\"]" }, +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_DD + { "dd", cmd_dd, 3, 6, "if=<infile> of=<outfile> [bs=<sectsize>] [count=<sectors>] [skip=<sectors>]" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_ECHO +# ifndef CONFIG_DISABLE_ENVIRON + { "echo", cmd_echo, 0, NSH_MAX_ARGUMENTS, "[<string|$name> [<string|$name>...]]" }, +# else + { "echo", cmd_echo, 0, NSH_MAX_ARGUMENTS, "[<string> [<string>...]]" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_EXEC + { "exec", cmd_exec, 2, 3, "<hex-address>" }, +#endif +#ifndef CONFIG_NSH_DISABLE_EXIT + { "exit", cmd_exit, 1, 1, NULL }, +#endif + +#ifndef CONFIG_NSH_DISABLE_FREE + { "free", cmd_free, 1, 1, NULL }, +#endif + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_GET + { "get", cmd_get, 4, 7, "[-b|-n] [-f <local-path>] -h <ip-address> <remote-path>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_HELP + { "help", cmd_help, 1, 1, NULL }, +#endif + +#ifdef CONFIG_NET +# ifndef CONFIG_NSH_DISABLE_IFCONFIG + { "ifconfig", cmd_ifconfig, 1, 3, "[nic_name [ip]]" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_SIGNALS +# ifndef CONFIG_NSH_DISABLE_KILL + { "kill", cmd_kill, 3, 3, "-<signal> <pid>" }, +# endif +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) +# ifndef CONFIG_NSH_DISABLE_LOSETUP + { "losetup", cmd_losetup, 3, 6, "[-d <dev-path>] | [[-o <offset>] [-r] <dev-path> <file-path>]" }, +# endif +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_LS + { "ls", cmd_ls, 1, 5, "[-lRs] <dir-path>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_MB + { "mb", cmd_mb, 2, 3, "<hex-address>[=<hex-value>][ <hex-byte-count>]" }, +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +# ifndef CONFIG_NSH_DISABLE_MKDIR + { "mkdir", cmd_mkdir, 2, 2, "<path>" }, +# endif +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_FAT) +# ifndef CONFIG_NSH_DISABLE_MKFATFS + { "mkfatfs", cmd_mkfatfs, 2, 2, "<path>" }, +# endif +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_MKFIFO + { "mkfifo", cmd_mkfifo, 2, 2, "<path>" }, +# endif +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +# ifndef CONFIG_NSH_DISABLE_MKRD + { "mkrd", cmd_mkrd, 2, 6, "[-m <minor>] [-s <sector-size>] <nsectors>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_MH + { "mh", cmd_mh, 2, 3, "<hex-address>[=<hex-value>][ <hex-byte-count>]" }, +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE) +# ifndef CONFIG_NSH_DISABLE_MOUNT + { "mount", cmd_mount, 4, 5, "-t <fstype> <block-device> <dir-path>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_MW + { "mw", cmd_mw, 2, 3, "<hex-address>[=<hex-value>][ <hex-byte-count>]" }, +#endif + +#if defined(CONFIG_NET) && defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ + !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_DISABLE_SIGNALS) +# ifndef CONFIG_NSH_DISABLE_PING + { "ping", cmd_ping, 2, 6, "[-c <count>] [-i <interval>] <ip-address>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_PS + { "ps", cmd_ps, 1, 1, NULL }, +#endif + +#if defined(CONFIG_NET_UDP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_PUT + { "put", cmd_put, 4, 7, "[-b|-n] [-f <remote-path>] -h <ip-address> <local-path>" }, +# endif +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_ENVIRON) +# ifndef CONFIG_NSH_DISABLE_PWD + { "pwd", cmd_pwd, 1, 1, NULL }, +# endif +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE) +# ifndef CONFIG_NSH_DISABLE_RM + { "rm", cmd_rm, 2, 2, "<file-path>" }, +# endif +# ifndef CONFIG_NSH_DISABLE_RMDIR + { "rmdir", cmd_rmdir, 2, 2, "<dir-path>" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_ENVIRON +# ifndef CONFIG_NSH_DISABLE_SET + { "set", cmd_set, 3, 3, "<name> <value>" }, +# endif +#endif + +#if CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0 && !defined(CONFIG_NSH_DISABLESCRIPT) +# ifndef CONFIG_NSH_DISABLE_SH + { "sh", cmd_sh, 2, 2, "<script-path>" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_SIGNALS +# ifndef CONFIG_NSH_DISABLE_SLEEP + { "sleep", cmd_sleep, 2, 2, "<sec>" }, +# endif +#endif + +#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_TEST) + { "test", cmd_test, 3, NSH_MAX_ARGUMENTS, "<expression>" }, +#endif + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_READABLE) +# ifndef CONFIG_NSH_DISABLE_UMOUNT + { "umount", cmd_umount, 2, 2, "<dir-path>" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_ENVIRON +# ifndef CONFIG_NSH_DISABLE_UNSET + { "unset", cmd_unset, 2, 2, "<name>" }, +# endif +#endif + +#ifndef CONFIG_DISABLE_SIGNALS +# ifndef CONFIG_NSH_DISABLE_USLEEP + { "usleep", cmd_usleep, 2, 2, "<usec>" }, +# endif +#endif + +#if defined(CONFIG_NET_TCP) && CONFIG_NFILE_DESCRIPTORS > 0 +# ifndef CONFIG_NSH_DISABLE_GET + { "wget", cmd_wget, 2, 4, "[-o <local-path>] <url>" }, +# endif +#endif + +#ifndef CONFIG_NSH_DISABLE_XD + { "xd", cmd_xd, 3, 3, "<hex-address> <byte-count>" }, +#endif + { NULL, NULL, 1, 1, NULL } +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* If NuttX versioning information is available, Include that information + * in the NSH greeting. + */ + +#if CONFIG_VERSION_MAJOR != 0 || CONFIG_VERSION_MINOR != 0 +const char g_nshgreeting[] = "\nNuttShell (NSH) NuttX-" CONFIG_VERSION_STRING "\n"; +#else +const char g_nshgreeting[] = "\nNuttShell (NSH)\n"; +#endif + +/* The NSH prompt */ + +const char g_nshprompt[] = "nsh> "; + +/* Common, message formats */ + +const char g_nshsyntax[] = "nsh: %s: syntax error\n"; +const char g_fmtargrequired[] = "nsh: %s: missing required argument(s)\n"; +const char g_fmtarginvalid[] = "nsh: %s: argument invalid\n"; +const char g_fmtargrange[] = "nsh: %s: value out of range\n"; +const char g_fmtcmdnotfound[] = "nsh: %s: command not found\n"; +const char g_fmtnosuch[] = "nsh: %s: no such %s: %s\n"; +const char g_fmttoomanyargs[] = "nsh: %s: too many arguments\n"; +const char g_fmtdeepnesting[] = "nsh: %s: nesting too deep\n"; +const char g_fmtcontext[] = "nsh: %s: not valid in this context\n"; +#ifdef CONFIG_NSH_STRERROR +const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %s\n"; +#else +const char g_fmtcmdfailed[] = "nsh: %s: %s failed: %d\n"; +#endif +const char g_fmtcmdoutofmemory[] = "nsh: %s: out of memory\n"; +const char g_fmtinternalerror[] = "nsh: %s: Internal error\n"; +#ifndef CONFIG_DISABLE_SIGNALS +const char g_fmtsignalrecvd[] = "nsh: %s: Interrupted by signal\n"; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_help + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_HELP +static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + const struct cmdmap_s *ptr; +#ifdef CONFIG_NSH_BUILTIN_APPS + FAR const char * name; + int i; +#endif + + nsh_output(vtbl, "NSH command forms:\n"); +#ifndef CONFIG_NSH_DISABLEBG + nsh_output(vtbl, " [nice [-d <niceness>>]] <cmd> [> <file>|>> <file>] [&]\n"); +#else + nsh_output(vtbl, " <cmd> [> <file>|>> <file>]\n"); +#endif +#ifndef CONFIG_NSH_DISABLESCRIPT + nsh_output(vtbl, "OR\n"); + nsh_output(vtbl, " if <cmd>\n"); + nsh_output(vtbl, " then\n"); + nsh_output(vtbl, " [sequence of <cmd>]\n"); + nsh_output(vtbl, " else\n"); + nsh_output(vtbl, " [sequence of <cmd>]\n"); + nsh_output(vtbl, " fi\n"); +#endif + nsh_output(vtbl, "Where <cmd> is one of:\n"); + for (ptr = g_cmdmap; ptr->cmd; ptr++) + { + if (ptr->usage) + { + nsh_output(vtbl, " %s %s\n", ptr->cmd, ptr->usage); + } + else + { + nsh_output(vtbl, " %s\n", ptr->cmd); + } + } + + /* List the set of available built-in commands */ + +#ifdef CONFIG_NSH_BUILTIN_APPS + nsh_output(vtbl, "\nBuiltin Apps:\n"); + for (i = 0; (name = namedapp_getname(i)) != NULL; i++) + { + nsh_output(vtbl, " %s\n", name); + } +#endif + + return OK; +} +#endif + +/**************************************************************************** + * Name: cmd_unrecognized + ****************************************************************************/ + +static int cmd_unrecognized(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + nsh_output(vtbl, g_fmtcmdnotfound, argv[0]); + return ERROR; +} + +/**************************************************************************** + * Name: cmd_exit + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_EXIT +static int cmd_exit(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + nsh_exit(vtbl); + return OK; +} +#endif + +/**************************************************************************** + * Name: nsh_execute + ****************************************************************************/ + +static int nsh_execute(FAR struct nsh_vtbl_s *vtbl, int argc, char *argv[]) +{ + const struct cmdmap_s *cmdmap; + const char *cmd; + cmd_t handler = cmd_unrecognized; + int ret; + + /* The form of argv is: + * + * argv[0]: The command name. This is argv[0] when the arguments + * are, finally, received by the command vtblr + * argv[1]: The beginning of argument (up to NSH_MAX_ARGUMENTS) + * argv[argc]: NULL terminating pointer + */ + + cmd = argv[0]; + + /* Try to find a command in the application library. + */ + +#ifdef CONFIG_NSH_BUILTIN_APPS + if (nsh_execapp(vtbl, cmd, argv) == OK) + { + /* The pre-built application was successfully started -- return OK. */ + + return OK; + } +#endif + + + /* See if the command is one that we understand */ + + for (cmdmap = g_cmdmap; cmdmap->cmd; cmdmap++) + { + if (strcmp(cmdmap->cmd, cmd) == 0) + { + /* Check if a valid number of arguments was provided. We + * do this simple, imperfect checking here so that it does + * not have to be performed in each command. + */ + + if (argc < cmdmap->minargs) + { + /* Fewer than the minimum number were provided */ + + nsh_output(vtbl, g_fmtargrequired, cmd); + return ERROR; + } + else if (argc > cmdmap->maxargs) + { + /* More than the maximum number were provided */ + + nsh_output(vtbl, g_fmttoomanyargs, cmd); + return ERROR; + } + else + { + /* A valid number of arguments were provided (this does + * not mean they are right). + */ + + handler = cmdmap->handler; + break; + } + } + } + + ret = handler(vtbl, argc, argv); + return ret; +} + +/**************************************************************************** + * Name: nsh_releaseargs + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static void nsh_releaseargs(struct cmdarg_s *arg) +{ + FAR struct nsh_vtbl_s *vtbl = arg->vtbl; + int i; + + /* If the output was redirected, then file descriptor should + * be closed. The created task has its one, independent copy of + * the file descriptor + */ + + if (vtbl->np.np_redirect) + { + (void)close(arg->fd); + } + + /* Released the cloned vtbl instance */ + + nsh_release(vtbl); + + /* Release the cloned args */ + + for (i = 0; i < arg->argc; i++) + { + free(arg->argv[i]); + } + free(arg); +} +#endif + +/**************************************************************************** + * Name: nsh_child + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static pthread_addr_t nsh_child(pthread_addr_t arg) +{ + struct cmdarg_s *carg = (struct cmdarg_s *)arg; + int ret; + + dbg("BG %s\n", carg->argv[0]); + + /* Execute the specified command on the child thread */ + + ret = nsh_execute(carg->vtbl, carg->argc, carg->argv); + + /* Released the cloned arguments */ + + dbg("BG %s complete\n", carg->argv[0]); + nsh_releaseargs(carg); + return (void*)ret; +} +#endif + +/**************************************************************************** + * Name: nsh_cloneargs + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static inline struct cmdarg_s *nsh_cloneargs(FAR struct nsh_vtbl_s *vtbl, + int fd, int argc, char *argv[]) +{ + struct cmdarg_s *ret = (struct cmdarg_s *)zalloc(sizeof(struct cmdarg_s)); + int i; + + if (ret) + { + ret->vtbl = vtbl; + ret->fd = fd; + ret->argc = argc; + + for (i = 0; i < argc; i++) + { + ret->argv[i] = strdup(argv[i]); + } + } + return ret; +} +#endif + +/**************************************************************************** + * Name: nsh_argument + ****************************************************************************/ + +char *nsh_argument(FAR struct nsh_vtbl_s *vtbl, char **saveptr) +{ + char *pbegin = *saveptr; + char *pend = NULL; + const char *term; +#ifndef CONFIG_DISABLE_ENVIRON + bool quoted = false; +#endif + + /* Find the beginning of the next token */ + + for (; + *pbegin && strchr(g_delim, *pbegin) != NULL; + pbegin++); + + /* If we are at the end of the string with nothing + * but delimiters found, then return NULL. + */ + + if (!*pbegin) + { + return NULL; + } + + /* Does the token begin with '>' -- redirection of output? */ + + if (*pbegin == '>') + { + /* Yes.. does it begin with ">>"? */ + + if (*(pbegin + 1) == '>') + { + *saveptr = pbegin + 2; + pbegin = (char*)g_redirect2; + } + else + { + *saveptr = pbegin + 1; + pbegin = (char*)g_redirect1; + } + } + + /* Does the token begin with '#' -- comment */ + + else if (*pbegin == '#') + { + /* Return NULL meaning that we are at the end of the line */ + + *saveptr = pbegin; + pbegin = NULL; + } + else + { + /* Otherwise, we are going to have to parse to find the end of + * the token. Does the token begin with '"'? + */ + + if (*pbegin == '"') + { + /* Yes.. then only another '"' can terminate the string */ + + pbegin++; + term = "\""; +#ifndef CONFIG_DISABLE_ENVIRON + quoted = true; +#endif + } + else + { + /* No, then any of the usual terminators will terminate the argument */ + + term = g_delim; + } + + /* Find the end of the string */ + + for (pend = pbegin + 1; + *pend && strchr(term, *pend) == NULL; + pend++); + + /* pend either points to the end of the string or to + * the first delimiter after the string. + */ + + if (*pend) + { + /* Turn the delimiter into a null terminator */ + + *pend++ = '\0'; + } + + /* Save the pointer where we left off */ + + *saveptr = pend; + +#ifndef CONFIG_DISABLE_ENVIRON + /* Check for references to environment variables */ + + if (pbegin[0] == '$' && !quoted) + { + /* Check for built-in variables */ + + if (strcmp(pbegin, g_exitstatus) == 0) + { + if (vtbl->np.np_fail) + { + return (char*)g_failure; + } + else + { + return (char*)g_success; + } + } + + /* Not a built-in? Return the value of the environment variable with this name */ + + else + { + char *value = getenv(pbegin+1); + if (value) + { + return value; + } + else + { + return (char*)""; + } + } + } +#endif + } + + /* Return the beginning of the token. */ + + return pbegin; +} + +/**************************************************************************** + * Name: nsh_cmdenabled + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLESCRIPT +static inline bool nsh_cmdenabled(FAR struct nsh_vtbl_s *vtbl) +{ + struct nsh_parser_s *np = &vtbl->np; + bool ret = !np->np_st[np->np_ndx].ns_disabled; + if (ret) + { + switch (np->np_st[np->np_ndx].ns_state) + { + case NSH_PARSER_NORMAL : + case NSH_PARSER_IF: + default: + break; + + case NSH_PARSER_THEN: + ret = !np->np_st[np->np_ndx].ns_ifcond; + break; + + case NSH_PARSER_ELSE: + ret = np->np_st[np->np_ndx].ns_ifcond; + break; + } + } + return ret; +} +#endif + +/**************************************************************************** + * Name: nsh_ifthenelse + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLESCRIPT +static inline int nsh_ifthenelse(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, FAR char **saveptr) +{ + struct nsh_parser_s *np = &vtbl->np; + FAR char *cmd = *ppcmd; + bool disabled; + + if (cmd) + { + /* Check if the command is preceeded by "if" */ + + if (strcmp(cmd, "if") == 0) + { + /* Get the cmd following the if */ + + *ppcmd = nsh_argument(vtbl, saveptr); + if (!*ppcmd) + { + nsh_output(vtbl, g_fmtarginvalid, "if"); + goto errout; + } + + /* Verify that "if" is valid in this context */ + + if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_NORMAL && + np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN && + np->np_st[np->np_ndx].ns_state != NSH_PARSER_ELSE) + { + nsh_output(vtbl, g_fmtcontext, "if"); + goto errout; + } + + /* Check if we have exceeded the maximum depth of nesting */ + + if (np->np_ndx >= CONFIG_NSH_NESTDEPTH-1) + { + nsh_output(vtbl, g_fmtdeepnesting, "if"); + goto errout; + } + + /* "Push" the old state and set the new state */ + + disabled = !nsh_cmdenabled(vtbl); + np->np_ndx++; + np->np_st[np->np_ndx].ns_state = NSH_PARSER_IF; + np->np_st[np->np_ndx].ns_disabled = disabled; + np->np_st[np->np_ndx].ns_ifcond = false; + } + else if (strcmp(cmd, "then") == 0) + { + /* Get the cmd following the then -- there shouldn't be one */ + + *ppcmd = nsh_argument(vtbl, saveptr); + if (*ppcmd) + { + nsh_output(vtbl, g_fmtarginvalid, "then"); + goto errout; + } + + /* Verify that "then" is valid in this context */ + + if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_IF) + { + nsh_output(vtbl, g_fmtcontext, "then"); + goto errout; + } + np->np_st[np->np_ndx].ns_state = NSH_PARSER_THEN; + } + else if (strcmp(cmd, "else") == 0) + { + /* Get the cmd following the else -- there shouldn't be one */ + + *ppcmd = nsh_argument(vtbl, saveptr); + if (*ppcmd) + { + nsh_output(vtbl, g_fmtarginvalid, "else"); + goto errout; + } + + /* Verify that "then" is valid in this context */ + + if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN) + { + nsh_output(vtbl, g_fmtcontext, "else"); + goto errout; + } + np->np_st[np->np_ndx].ns_state = NSH_PARSER_ELSE; + } + else if (strcmp(cmd, "fi") == 0) + { + /* Get the cmd following the fi -- there should be one */ + + *ppcmd = nsh_argument(vtbl, saveptr); + if (*ppcmd) + { + nsh_output(vtbl, g_fmtarginvalid, "fi"); + goto errout; + } + + /* Verify that "fi" is valid in this context */ + + if (np->np_st[np->np_ndx].ns_state != NSH_PARSER_THEN && + np->np_st[np->np_ndx].ns_state != NSH_PARSER_ELSE) + { + nsh_output(vtbl, g_fmtcontext, "fi"); + goto errout; + } + + if (np->np_ndx < 1) /* Shouldn't happen */ + { + nsh_output(vtbl, g_fmtinternalerror, "if"); + goto errout; + } + + /* "Pop" the previous state */ + + np->np_ndx--; + } + else if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF) + { + nsh_output(vtbl, g_fmtcontext, cmd); + goto errout; + } + } + return OK; + +errout: + np->np_ndx = 0; + np->np_st[0].ns_state = NSH_PARSER_NORMAL; + np->np_st[0].ns_disabled = false; + np->np_st[0].ns_ifcond = false; + return ERROR; +} +#endif + +/**************************************************************************** + * Name: nsh_saveresult + ****************************************************************************/ + +static inline int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result) +{ + struct nsh_parser_s *np = &vtbl->np; + +#ifndef CONFIG_NSH_DISABLESCRIPT + if (np->np_st[np->np_ndx].ns_state == NSH_PARSER_IF) + { + np->np_fail = false; + np->np_st[np->np_ndx].ns_ifcond = result; + return OK; + } + else +#endif + { + np->np_fail = result; + return result ? ERROR : OK; + } +} + +/**************************************************************************** + * Name: nsh_nice + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static inline int nsh_nice(FAR struct nsh_vtbl_s *vtbl, FAR char **ppcmd, FAR char **saveptr) +{ + FAR char *cmd = *ppcmd; + + vtbl->np.np_nice = 0; + if (cmd) + { + /* Check if the command is preceded by "nice" */ + + if (strcmp(cmd, "nice") == 0) + { + /* Nicenesses range from -20 (most favorable scheduling) to 19 + * (least favorable). Default is 10. + */ + + vtbl->np.np_nice = 10; + + /* Get the cmd (or -d option of nice command) */ + + cmd = nsh_argument(vtbl, saveptr); + if (cmd && strcmp(cmd, "-d") == 0) + { + FAR char *val = nsh_argument(vtbl, saveptr); + if (val) + { + char *endptr; + vtbl->np.np_nice = (int)strtol(val, &endptr, 0); + if (vtbl->np.np_nice > 19 || vtbl->np.np_nice < -20 || + endptr == val || *endptr != '\0') + { + nsh_output(vtbl, g_fmtarginvalid, "nice"); + return ERROR; + } + cmd = nsh_argument(vtbl, saveptr); + } + } + + /* Return the real command name */ + + *ppcmd = cmd; + } + } + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_initialize + ****************************************************************************/ + +void nsh_initialize(void) +{ + /* Mount the /etc filesystem */ + + (void)nsh_romfsetc(); + + /* Perform architecture-specific initialization (if available) */ + + (void)nsh_archinitialize(); + + /* Bring up the network */ + + (void)nsh_netinit(); +} + +/**************************************************************************** + * Name: nsh_parse + ****************************************************************************/ + +int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline) +{ + FAR char *argv[MAX_ARGV_ENTRIES]; + FAR char *saveptr; + FAR char *cmd; + FAR char *redirfile = NULL; + int fd = -1; + int oflags = 0; + int argc; + int ret; + + /* Initialize parser state */ + + memset(argv, 0, MAX_ARGV_ENTRIES*sizeof(FAR char *)); +#ifndef CONFIG_NSH_DISABLEBG + vtbl->np.np_bg = false; +#endif + vtbl->np.np_redirect = false; + + /* Parse out the command at the beginning of the line */ + + saveptr = cmdline; + cmd = nsh_argument(vtbl, &saveptr); + + /* Handler if-then-else-fi */ + +#ifndef CONFIG_NSH_DISABLESCRIPT + if (nsh_ifthenelse(vtbl, &cmd, &saveptr) != 0) + { + goto errout; + } +#endif + + /* Handle nice */ + +#ifndef CONFIG_NSH_DISABLEBG + if (nsh_nice(vtbl, &cmd, &saveptr) != 0) + { + goto errout; + } +#endif + + /* Check if any command was provided -OR- if command processing is + * currently disabled. + */ + +#ifndef CONFIG_NSH_DISABLESCRIPT + if (!cmd || !nsh_cmdenabled(vtbl)) +#else + if (!cmd) +#endif + { + /* An empty line is not an error and an unprocessed command cannot + * generate an error, but neither should they change the last + * command status. + */ + + return OK; + } + + /* Parse all of the arguments following the command name. The form + * of argv is: + * + * argv[0]: The command name. + * argv[1]: The beginning of argument (up to NSH_MAX_ARGUMENTS) + * argv[argc-3]: Possibly '>' or '>>' + * argv[argc-2]: Possibly <file> + * argv[argc-1]: Possibly '&' + * argv[argc]: NULL terminating pointer + * + * Maximum size is NSH_MAX_ARGUMENTS+5 + */ + + argv[0] = cmd; + for (argc = 1; argc < MAX_ARGV_ENTRIES-1; argc++) + { + argv[argc] = nsh_argument(vtbl, &saveptr); + if (!argv[argc]) + { + break; + } + } + argv[argc] = NULL; + + /* Check if the command should run in background */ + +#ifndef CONFIG_NSH_DISABLEBG + if (argc > 1 && strcmp(argv[argc-1], "&") == 0) + { + vtbl->np.np_bg = true; + argv[argc-1] = NULL; + argc--; + } +#endif + + + /* Check if the output was re-directed using > or >> */ + + if (argc > 2) + { + /* Check for redirection to a new file */ + + if (strcmp(argv[argc-2], g_redirect1) == 0) + { + vtbl->np.np_redirect = true; + oflags = O_WRONLY|O_CREAT|O_TRUNC; + redirfile = nsh_getfullpath(vtbl, argv[argc-1]); + argc -= 2; + } + + /* Check for redirection by appending to an existing file */ + + else if (strcmp(argv[argc-2], g_redirect2) == 0) + { + vtbl->np.np_redirect = true; + oflags = O_WRONLY|O_CREAT|O_APPEND; + redirfile = nsh_getfullpath(vtbl, argv[argc-1]); + argc -= 2; + } + } + + /* Redirected output? */ + + if (vtbl->np.np_redirect) + { + /* Open the redirection file. This file will eventually + * be closed by a call to either nsh_release (if the command + * is executed in the background) or by nsh_undirect if the + * command is executed in the foreground. + */ + + fd = open(redirfile, oflags, 0666); + nsh_freefullpath(redirfile); + redirfile = NULL; + + if (fd < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO); + goto errout; + } + } + + /* Check if the maximum number of arguments was exceeded */ + + if (argc > NSH_MAX_ARGUMENTS) + { + nsh_output(vtbl, g_fmttoomanyargs, cmd); + } + + /* Handle the case where the command is executed in background. + * However is app is to be started as namedapp new process will + * be created anyway, so skip this step. */ + +#ifndef CONFIG_NSH_DISABLEBG + if (vtbl->np.np_bg +#ifdef CONFIG_NSH_BUILTIN_APPS + && namedapp_isavail(argv[0]) < 0 +#endif + ) + { + struct sched_param param; + struct nsh_vtbl_s *bkgvtbl; + struct cmdarg_s *args; + pthread_attr_t attr; + pthread_t thread; + + /* Get a cloned copy of the vtbl with reference count=1. + * after the command has been processed, the nsh_release() call + * at the end of nsh_child() will destroy the clone. + */ + + bkgvtbl = nsh_clone(vtbl); + if (!bkgvtbl) + { + goto errout_with_redirect; + } + + /* Create a container for the command arguments */ + + args = nsh_cloneargs(bkgvtbl, fd, argc, argv); + if (!args) + { + nsh_release(bkgvtbl); + goto errout_with_redirect; + } + + /* Handle redirection of output via a file descriptor */ + + if (vtbl->np.np_redirect) + { + (void)nsh_redirect(bkgvtbl, fd, NULL); + } + + /* Get the execution priority of this task */ + + ret = sched_getparam(0, ¶m); + if (ret != 0) + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "sched_getparm", NSH_ERRNO); + nsh_releaseargs(args); + nsh_release(bkgvtbl); + goto errout; + } + + /* Determine the priority to execute the command */ + + if (vtbl->np.np_nice != 0) + { + int priority = param.sched_priority - vtbl->np.np_nice; + if (vtbl->np.np_nice < 0) + { + int max_priority = sched_get_priority_max(SCHED_NSH); + if (priority > max_priority) + { + priority = max_priority; + } + } + else + { + int min_priority = sched_get_priority_min(SCHED_NSH); + if (priority < min_priority) + { + priority = min_priority; + } + } + param.sched_priority = priority; + } + + /* Set up the thread attributes */ + + (void)pthread_attr_init(&attr); + (void)pthread_attr_setschedpolicy(&attr, SCHED_NSH); + (void)pthread_attr_setschedparam(&attr, ¶m); + + /* Execute the command as a separate thread at the appropriate priority */ + + ret = pthread_create(&thread, &attr, nsh_child, (pthread_addr_t)args); + if (ret != 0) + { + nsh_output(vtbl, g_fmtcmdfailed, cmd, "pthread_create", NSH_ERRNO_OF(ret)); + nsh_releaseargs(args); + nsh_release(bkgvtbl); + goto errout; + } + nsh_output(vtbl, "%s [%d:%d]\n", cmd, thread, param.sched_priority); + } + else +#endif + { + uint8_t save[SAVE_SIZE]; + + /* Handle redirection of output via a file descriptor */ + + if (vtbl->np.np_redirect) + { + nsh_redirect(vtbl, fd, save); + } + + /* Then execute the command in "foreground" -- i.e., while the user waits + * for the next prompt. + */ + + ret = nsh_execute(vtbl, argc, argv); + + /* Restore the original output. Undirect will close the redirection + * file descriptor. + */ + + if (vtbl->np.np_redirect) + { + nsh_undirect(vtbl, save); + } + + if (ret < 0) + { + goto errout; + } + } + + /* Return success if the command succeeded (or at least, starting of the + * command task succeeded). + */ + + return nsh_saveresult(vtbl, false); + +#ifndef CONFIG_NSH_DISABLEBG +errout_with_redirect: + if (vtbl->np.np_redirect) + { + close(fd); + } +#endif +errout: + return nsh_saveresult(vtbl, true); +} diff --git a/apps/nshlib/nsh_proccmds.c b/apps/nshlib/nsh_proccmds.c new file mode 100644 index 000000000..c0dc1713f --- /dev/null +++ b/apps/nshlib/nsh_proccmds.c @@ -0,0 +1,309 @@ +/**************************************************************************** + * apps/nshlib/nsh_proccmds.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sched.h> +#include <errno.h> + +#include "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The returned value should be zero for sucess or TRUE or non zero for + * failure or FALSE. + */ + +typedef int (*exec_t)(void); + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_PS +static const char *g_statenames[] = +{ + "INVALID ", + "PENDING ", + "READY ", + "RUNNING ", + "INACTIVE", + "WAITSEM ", +#ifndef CONFIG_DISABLE_MQUEUE + "WAITSIG ", +#endif +#ifndef CONFIG_DISABLE_MQUEUE + "MQNEMPTY", + "MQNFULL " +#endif +}; + +static const char *g_ttypenames[4] = +{ + "TASK ", + "PTHREAD", + "KTHREAD", + "--?-- " +}; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ps_task + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_PS +static void ps_task(FAR _TCB *tcb, FAR void *arg) +{ + struct nsh_vtbl_s *vtbl = (struct nsh_vtbl_s*)arg; +#if CONFIG_MAX_TASK_ARGS > 2 + int i; +#endif + + /* Show task status */ + + nsh_output(vtbl, "%5d %3d %4s %7s%c%c %8s ", + tcb->pid, tcb->sched_priority, + tcb->flags & TCB_FLAG_ROUND_ROBIN ? "RR " : "FIFO", + g_ttypenames[(tcb->flags & TCB_FLAG_TTYPE_MASK) >> TCB_FLAG_TTYPE_SHIFT], + tcb->flags & TCB_FLAG_NONCANCELABLE ? 'N' : ' ', + tcb->flags & TCB_FLAG_CANCEL_PENDING ? 'P' : ' ', + g_statenames[tcb->task_state]); + + /* Show task name and arguments */ + + nsh_output(vtbl, "%s(", tcb->argv[0]); + + /* Special case 1st argument (no comma) */ + + if (tcb->argv[1]) + { + nsh_output(vtbl, "%p", tcb->argv[1]); + } + + /* Then any additional arguments */ + +#if CONFIG_MAX_TASK_ARGS > 2 + for (i = 2; i <= CONFIG_MAX_TASK_ARGS && tcb->argv[i]; i++) + { + nsh_output(vtbl, ", %p", tcb->argv[i]); + } +#endif + nsh_output(vtbl, ")\n"); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_exec + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_EXEC +int cmd_exec(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *endptr; + uintptr_t addr; + + addr = (uintptr_t)strtol(argv[1], &endptr, 0); + if (!addr || endptr == argv[1] || *endptr != '\0') + { + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + return ERROR; + } + + nsh_output(vtbl, "Calling %p\n", (exec_t)addr); + return ((exec_t)addr)(); +} +#endif + +/**************************************************************************** + * Name: cmd_ps + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLE_PS +int cmd_ps(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + nsh_output(vtbl, "PID PRI SCHD TYPE NP STATE NAME\n"); + sched_foreach(ps_task, vtbl); + return OK; +} +#endif + +/**************************************************************************** + * Name: cmd_kill + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_SIGNALS +#ifndef CONFIG_NSH_DISABLE_KILL +int cmd_kill(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *ptr; + char *endptr; + long signal; + long pid; + + /* Check incoming parameters. The first parameter should be "-<signal>" */ + + ptr = argv[1]; + if (*ptr != '-' || ptr[1] < '0' || ptr[1] > '9') + { + goto invalid_arg; + } + + /* Extract the signal number */ + + signal = strtol(&ptr[1], &endptr, 0); + + /* The second parameter should be <pid> */ + + ptr = argv[2]; + if (*ptr < '0' || *ptr > '9') + { + goto invalid_arg; + } + + /* Extract athe pid */ + + pid = strtol(ptr, &endptr, 0); + + /* Send the signal. Kill return values: + * + * EINVAL An invalid signal was specified. + * EPERM The process does not have permission to send the signal to any + * of the target processes. + * ESRCH The pid or process group does not exist. + * ENOSYS Do not support sending signals to process groups. + */ + + if (kill((pid_t)pid, (int)signal) == 0) + { + return OK; + } + + switch (errno) + { + case EINVAL: + goto invalid_arg; + + case ESRCH: + nsh_output(vtbl, g_fmtnosuch, argv[0], "task", argv[2]); + return ERROR; + + case EPERM: + case ENOSYS: + default: + nsh_output(vtbl, g_fmtcmdfailed, argv[0], "kill", NSH_ERRNO); + return ERROR; + } + +invalid_arg: + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + return ERROR; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_sleep + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_SIGNALS +#ifndef CONFIG_NSH_DISABLE_SLEEP +int cmd_sleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *endptr; + long secs; + + secs = strtol(argv[1], &endptr, 0); + if (!secs || endptr == argv[1] || *endptr != '\0') + { + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + return ERROR; + } + sleep(secs); + return OK; +} +#endif +#endif + +/**************************************************************************** + * Name: cmd_usleep + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_SIGNALS +#ifndef CONFIG_NSH_DISABLE_USLEEP +int cmd_usleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + char *endptr; + long usecs; + + usecs = strtol(argv[1], &endptr, 0); + if (!usecs || endptr == argv[1] || *endptr != '\0') + { + nsh_output(vtbl, g_fmtarginvalid, argv[0]); + return ERROR; + } + usleep(usecs); + return OK; +} +#endif +#endif diff --git a/apps/nshlib/nsh_romfsetc.c b/apps/nshlib/nsh_romfsetc.c new file mode 100644 index 000000000..d97e6591a --- /dev/null +++ b/apps/nshlib/nsh_romfsetc.c @@ -0,0 +1,124 @@ +/**************************************************************************** + * apps/nshlib/nsh_romfsetc.c + * + * Copyright (C) 2008-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/mount.h> +#include <debug.h> +#include <errno.h> + +#include <nuttx/ramdisk.h> + +#include "nsh.h" + +#ifdef CONFIG_NSH_ROMFSETC + +/* Should we use the default ROMFS image? Or a custom, board-specific + * ROMFS image? + */ + +#ifdef CONFIG_NSH_ARCHROMFS +# include <arch/board/nsh_romfsimg.h> +#else +# include "nsh_romfsimg.h" +#endif + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_romfsetc + ****************************************************************************/ + +int nsh_romfsetc(void) +{ + int ret; + + /* Create a ROM disk for the /etc filesystem */ + + ret = romdisk_register(CONFIG_NSH_ROMFSDEVNO, romfs_img, + NSECTORS(romfs_img_len), CONFIG_NSH_ROMFSSECTSIZE); + if (ret < 0) + { + dbg("nsh: romdisk_register failed: %d\n", -ret); + return ERROR; + } + + /* Mount the file system */ + + vdbg("Mounting ROMFS filesystem at target=%s with source=%s\n", + CONFIG_NSH_ROMFSMOUNTPT, MOUNT_DEVNAME); + + ret = mount(MOUNT_DEVNAME, CONFIG_NSH_ROMFSMOUNTPT, "romfs", MS_RDONLY, NULL); + if (ret < 0) + { + dbg("nsh: mount(%s,%s,romfs) failed: %d\n", + MOUNT_DEVNAME, CONFIG_NSH_ROMFSMOUNTPT, errno); + return ERROR; + } + return OK; +} + +#endif /* CONFIG_NSH_ROMFSETC */ + diff --git a/apps/nshlib/nsh_romfsimg.h b/apps/nshlib/nsh_romfsimg.h new file mode 100644 index 000000000..49b0ad166 --- /dev/null +++ b/apps/nshlib/nsh_romfsimg.h @@ -0,0 +1,89 @@ +unsigned char romfs_img[] = { + 0x2d, 0x72, 0x6f, 0x6d, 0x31, 0x66, 0x73, 0x2d, 0x00, 0x00, 0x01, 0x50, + 0x9f, 0x13, 0x82, 0x87, 0x4e, 0x53, 0x48, 0x49, 0x6e, 0x69, 0x74, 0x56, + 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xff, 0x97, + 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xff, 0x80, 0x2e, 0x2e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x2d, 0x96, 0x03, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x64, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xff, 0xff, 0x00, + 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6e, 0x8d, 0x9c, 0xab, 0x58, 0x72, 0x63, 0x53, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x52, + 0x41, 0x4d, 0x44, 0x49, 0x53, 0x4b, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x69, 0x74, 0x20, 0x61, 0x74, 0x20, 0x2f, + 0x74, 0x6d, 0x70, 0x0a, 0x0a, 0x6d, 0x6b, 0x72, 0x64, 0x20, 0x2d, 0x6d, + 0x20, 0x32, 0x20, 0x2d, 0x73, 0x20, 0x35, 0x31, 0x32, 0x20, 0x31, 0x30, + 0x32, 0x34, 0x0a, 0x6d, 0x6b, 0x66, 0x61, 0x74, 0x66, 0x73, 0x20, 0x2f, + 0x64, 0x65, 0x76, 0x2f, 0x72, 0x61, 0x6d, 0x32, 0x0a, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x20, 0x2d, 0x74, 0x20, 0x76, 0x66, 0x61, 0x74, 0x20, 0x2f, + 0x64, 0x65, 0x76, 0x2f, 0x72, 0x61, 0x6d, 0x32, 0x20, 0x2f, 0x74, 0x6d, + 0x70, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xff, 0xe0, 0x2e, 0x2e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +unsigned int romfs_img_len = 1024; diff --git a/apps/nshlib/nsh_serial.c b/apps/nshlib/nsh_serial.c new file mode 100644 index 000000000..ccb25477d --- /dev/null +++ b/apps/nshlib/nsh_serial.c @@ -0,0 +1,508 @@ +/**************************************************************************** + * apps/nshlib/nsh_serial.c + * + * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdarg.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include "nsh.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Are we using the NuttX console for I/O? Or some other character device? */ + +#ifdef CONFIG_NSH_CONDEV +# define INFD(p) ((p)->ss_confd) +# define INSTREAM(p) ((p)->ss_constream) +# define OUTFD(p) ((p)->ss_confd) +# define OUTSTREAM(p) ((p)->ss_constream) +#else +# define INFD(p) 0 +# define INSTREAM(p) stdin +# define OUTFD(p) 1 +# define OUTSTREAM(p) stdout +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct serial_s +{ + /* NSH front-end call table */ + + struct nsh_vtbl_s ss_vtbl; + + /* NSH input/output streams */ + +#ifdef CONFIG_NSH_CONDEV + int ss_confd; /* Console I/O file descriptor */ +#endif + int ss_outfd; /* Output file descriptor (possibly redirected) */ +#ifdef CONFIG_NSH_CONDEV + FILE *ss_constream; /* Console I/O stream (possibly redirected) */ +#endif + FILE *ss_outstream; /* Output stream */ + + /* Line input buffer */ + + char ss_line[CONFIG_NSH_LINELEN]; +}; + +struct serialsave_s +{ + int ss_outfd; /* Re-directed output file descriptor */ + FILE *ss_outstream; /* Re-directed output stream */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl); +static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl); +#endif +static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes); +static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); +static FAR char *nsh_consolelinebuffer(FAR struct nsh_vtbl_s *vtbl); +static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save); +static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save); +static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_allocstruct + ****************************************************************************/ + +static inline FAR struct serial_s *nsh_allocstruct(void) +{ + struct serial_s *pstate = (struct serial_s *)zalloc(sizeof(struct serial_s)); + if (pstate) + { + /* Initialize the call table */ + +#ifndef CONFIG_NSH_DISABLEBG + pstate->ss_vtbl.clone = nsh_consoleclone; + pstate->ss_vtbl.release = nsh_consolerelease; +#endif + pstate->ss_vtbl.write = nsh_consolewrite; + pstate->ss_vtbl.output = nsh_consoleoutput; + pstate->ss_vtbl.linebuffer = nsh_consolelinebuffer; + pstate->ss_vtbl.redirect = nsh_consoleredirect; + pstate->ss_vtbl.undirect = nsh_consoleundirect; + pstate->ss_vtbl.exit = nsh_consoleexit; + + /* (Re-) open the console input device */ + +#ifdef CONFIG_NSH_CONDEV + pstate->ss_confd = open(CONFIG_NSH_CONDEV, O_RDWR); + if (pstate->ss_confd < 0) + { + free(pstate); + return NULL; + } + + /* Create a standard C stream on the console device */ + + pstate->ss_constream = fdopen(pstate->ss_confd, "r+"); + if (!pstate->ss_constream) + { + close(pstate->ss_confd); + free(pstate); + return NULL; + } +#endif + + /* Initialize the output stream */ + + pstate->ss_outfd = OUTFD(pstate); + pstate->ss_outstream = OUTSTREAM(pstate); + } + return pstate; +} + +/**************************************************************************** + * Name: nsh_openifnotopen + ****************************************************************************/ + +static int nsh_openifnotopen(struct serial_s *pstate) +{ + /* The stream is open in a lazy fashion. This is done because the file + * descriptor may be opened on a different task than the stream. + */ + + if (!pstate->ss_outstream) + { + pstate->ss_outstream = fdopen(pstate->ss_outfd, "w"); + if (!pstate->ss_outstream) + { + return ERROR; + } + } + return 0; +} + +/**************************************************************************** + * Name: nsh_closeifnotclosed + * + * Description: + * Close the output stream if it is not the standard output stream. + * + ****************************************************************************/ + +static void nsh_closeifnotclosed(struct serial_s *pstate) +{ + if (pstate->ss_outstream == OUTSTREAM(pstate)) + { + fflush(OUTSTREAM(pstate)); + pstate->ss_outfd = OUTFD(pstate); + } + else + { + if (pstate->ss_outstream) + { + fflush(pstate->ss_outstream); + fclose(pstate->ss_outstream); + } + else if (pstate->ss_outfd >= 0 && pstate->ss_outfd != OUTFD(pstate)) + { + close(pstate->ss_outfd); + } + + pstate->ss_outfd = -1; + pstate->ss_outstream = NULL; + } +} + +/**************************************************************************** + * Name: nsh_consolewrite + * + * Description: + * write a buffer to the remote shell window. + * + * Currently only used by cat. + * + ****************************************************************************/ + +static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes) +{ + FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl; + ssize_t ret; + + /* The stream is open in a lazy fashion. This is done because the file + * descriptor may be opened on a different task than the stream. The + * actual open will then occur with the first output from the new task. + */ + + if (nsh_openifnotopen(pstate) != 0) + { + return (ssize_t)ERROR; + } + + /* Write the data to the output stream */ + + ret = fwrite(buffer, 1, nbytes, pstate->ss_outstream); + if (ret < 0) + { + dbg("[%d] Failed to send buffer: %d\n", pstate->ss_outfd, errno); + } + return ret; +} + +/**************************************************************************** + * Name: nsh_consoleoutput + * + * Description: + * Print a string to the currently selected stream. + * + ****************************************************************************/ + +static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) +{ + FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl; + va_list ap; + int ret; + + /* The stream is open in a lazy fashion. This is done because the file + * descriptor may be opened on a different task than the stream. The + * actual open will then occur with the first output from the new task. + */ + + if (nsh_openifnotopen(pstate) != 0) + { + return ERROR; + } + + va_start(ap, fmt); + ret = vfprintf(pstate->ss_outstream, fmt, ap); + va_end(ap); + + return ret; +} + +/**************************************************************************** + * Name: nsh_consolelinebuffer + * + * Description: + * Return a reference to the current line buffer + * + ****************************************************************************/ + +static FAR char *nsh_consolelinebuffer(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl; + return pstate->ss_line; +} + +/**************************************************************************** + * Name: nsh_consoleclone + * + * Description: + * Make an independent copy of the vtbl + * + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct serial_s *pclone = nsh_allocstruct(); + return &pclone->ss_vtbl; +} +#endif + +/**************************************************************************** + * Name: nsh_consolerelease + * + * Description: + * Release the cloned instance + * + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl; + + /* Close the output stream */ + + nsh_closeifnotclosed(pstate); + + /* Close the console stream */ + +#ifdef CONFIG_NSH_CONDEV + (void)fclose(pstate->ss_constream); +#endif + + /* Then release the vtable container */ + + free(pstate); +} +#endif + +/**************************************************************************** + * Name: nsh_consoleredirect + * + * Description: + * Set up for redirected output. This function is called from nsh_parse() + * in two different contexts: + * + * 1) Redirected background commands of the form: command > xyz.text & + * + * In this case: + * - vtbl: A newly allocated and initialized instance created by + * nsh_consoleclone, + * - fd:- The file descriptor of the redirected output + * - save: NULL + * + * nsh_consolerelease() will perform the clean-up when the clone is + * destroyed. + * + * 2) Redirected foreground commands of the form: command > xyz.txt + * + * In this case: + * - vtbl: The current state structure, + * - fd: The file descriptor of the redirected output + * - save: Where to save the re-directed registers. + * + * nsh_consoleundirect() will perform the clean-up after the redirected + * command completes. + * + ****************************************************************************/ + +static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save) +{ + FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl; + FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save; + + /* Case 1: Redirected foreground commands */ + + if (ssave) + { + /* pstate->ss_outstream and ss_outfd refer refer to the + * currently opened output stream. If the output stream is open, flush + * any pending output. + */ + + if (pstate->ss_outstream) + { + fflush(pstate->ss_outstream); + } + + /* Save the current fd and stream values. These will be restored + * when nsh_consoleundirect() is called. + */ + + ssave->ss_outfd = pstate->ss_outfd; + ssave->ss_outstream = pstate->ss_outstream; + } + else + { + /* nsh_consoleclone() set pstate->ss_outfd and ss_outstream to refer + * to standard out. We just want to leave these alone and overwrite + * them with the fd for the re-directed stream. + */ + } + + /* In either case, set the fd of the new, re-directed output and nullify + * the output stream (it will be fdopen'ed if it is used). + */ + + pstate->ss_outfd = fd; + pstate->ss_outstream = NULL; +} + +/**************************************************************************** + * Name: nsh_consoleundirect + * + * Description: + * Set up for redirected output + * + ****************************************************************************/ + +static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save) +{ + FAR struct serial_s *pstate = (FAR struct serial_s *)vtbl; + FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save; + + nsh_closeifnotclosed(pstate); + pstate->ss_outfd = ssave->ss_outfd; + pstate->ss_outstream = ssave->ss_outstream; +} + +/**************************************************************************** + * Name: nsh_consoleexit + * + * Description: + * Exit the shell task + * + ****************************************************************************/ + +static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl) +{ + exit(0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_consolemain + ****************************************************************************/ + +int nsh_consolemain(int argc, char *argv[]) +{ + FAR struct serial_s *pstate = nsh_allocstruct(); + DEBUGASSERT(pstate); + + /* Present a greeting */ + + fputs(g_nshgreeting, pstate->ss_outstream); + fflush(pstate->ss_outstream); + + /* Execute the startup script */ + +#ifdef CONFIG_NSH_ROMFSETC + (void)nsh_script(&pstate->ss_vtbl, "init", NSH_INITPATH); +#endif + + /* Then enter the command line parsing loop */ + + for (;;) + { + /* Display the prompt string */ + + fputs(g_nshprompt, pstate->ss_outstream); + fflush(pstate->ss_outstream); + + /* Get the next line of input */ + + if (fgets(pstate->ss_line, CONFIG_NSH_LINELEN, INSTREAM(pstate))) + { + /* Parse process the command */ + + (void)nsh_parse(&pstate->ss_vtbl, pstate->ss_line); + fflush(pstate->ss_outstream); + } + } + return OK; +} diff --git a/apps/nshlib/nsh_telnetd.c b/apps/nshlib/nsh_telnetd.c new file mode 100644 index 000000000..0670c9a05 --- /dev/null +++ b/apps/nshlib/nsh_telnetd.c @@ -0,0 +1,853 @@ +/**************************************************************************** + * apps/nshlib/nsh_telnetd.c + * + * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * This is a leverage of similar logic from uIP: + * + * Author: Adam Dunkels <adam@sics.se> + * Copyright (c) 2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <pthread.h> +#include <semaphore.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <net/if.h> +#include <apps/netutils/uiplib.h> +#if defined(CONFIG_NSH_DHCPC) +# include <apps/netutils/resolv.h> +# include <apps/netutils/dhcpc.h> +#endif + +#include "nsh.h" + +#ifdef CONFIG_NSH_TELNET + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +#define STATE_NORMAL 0 +#define STATE_IAC 1 +#define STATE_WILL 2 +#define STATE_WONT 3 +#define STATE_DO 4 +#define STATE_DONT 5 +#define STATE_CLOSE 6 + +#define TELNET_IAC 255 +#define TELNET_WILL 251 +#define TELNET_WONT 252 +#define TELNET_DO 253 +#define TELNET_DONT 254 + +#ifdef CONFIG_NSH_TELNETD_DUMPBUFFER +# define nsh_telnetdump(vtbl,msg,buf,nb) nsh_dumpbuffer(vtbl,msg,buf,nb) +#else +# define nsh_telnetdump(vtbl,msg,buf,nb) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct telnetio_s +{ + sem_t tio_sem; + int tio_sockfd; + uint8_t tio_bufndx; + uint8_t tio_state; + char tio_inbuffer[CONFIG_NSH_IOBUFFER_SIZE]; +}; + +struct redirect_s +{ + int rd_fd; /* Re-direct file descriptor */ + FILE *rd_stream; /* Re-direct stream */ +}; + +struct telnetsave_s +{ + bool ts_redirected; + union + { + struct telnetio_s *tn; + struct redirect_s rd; + } u; +}; + +struct telnetd_s +{ + struct nsh_vtbl_s tn_vtbl; + uint16_t tn_sndlen; + bool tn_redirected; + union + { + struct telnetio_s *tn; + struct redirect_s rd; + } u; + char tn_outbuffer[CONFIG_NSH_IOBUFFER_SIZE]; + char tn_cmd[CONFIG_NSH_LINELEN]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static void tio_semtake(struct telnetio_s *tio); +static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl); +#endif +static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl); +static ssize_t nsh_telnetwrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes); +static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); +static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); +static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl); +static void nsh_telnetredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save); +static void nsh_telnetundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save); +static void nsh_telnetexit(FAR struct nsh_vtbl_s *vtbl); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tio_semtake + ****************************************************************************/ + +static void tio_semtake(struct telnetio_s *tio) +{ + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(&tio->tio_sem) != 0) + { + /* The only case that an error should occur here is if the wait was + * awakened by a signal. + */ + + ASSERT(errno == EINTR); + } +} + +/**************************************************************************** + * Name: tio_semgive + ****************************************************************************/ + +#define tio_semgive(tio) ASSERT(sem_post(&tio->tio_sem) == 0) + +/**************************************************************************** + * Name: nsh_allocstruct + ****************************************************************************/ + +static FAR struct telnetd_s *nsh_allocstruct(void) +{ + struct telnetd_s *pstate = (struct telnetd_s *)zalloc(sizeof(struct telnetd_s)); + if (pstate) + { +#ifndef CONFIG_NSH_DISABLEBG + pstate->tn_vtbl.clone = nsh_telnetclone; + pstate->tn_vtbl.release = nsh_telnetrelease; +#endif + pstate->tn_vtbl.write = nsh_telnetwrite; + pstate->tn_vtbl.output = nsh_telnetoutput; + pstate->tn_vtbl.linebuffer = nsh_telnetlinebuffer; + pstate->tn_vtbl.redirect = nsh_telnetredirect; + pstate->tn_vtbl.undirect = nsh_telnetundirect; + pstate->tn_vtbl.exit = nsh_telnetexit; + } + return pstate; +} + +/**************************************************************************** + * Name: nsh_openifnotopen + ****************************************************************************/ + +static int nsh_openifnotopen(struct telnetd_s *pstate) +{ + struct redirect_s *rd = &pstate->u.rd; + + /* The stream is open in a lazy fashion. This is done because the file + * descriptor may be opened on a different task than the stream. + */ + + if (!rd->rd_stream) + { + rd->rd_stream = fdopen(rd->rd_fd, "w"); + if (!rd->rd_stream) + { + return ERROR; + } + } + return 0; +} + +/**************************************************************************** + * Name: nsh_closeifnotclosed + ****************************************************************************/ + +static void nsh_closeifnotclosed(struct telnetd_s *pstate) +{ + struct redirect_s *rd = &pstate->u.rd; + + if (rd->rd_stream == stdout) + { + fflush(stdout); + rd->rd_fd = 1; + } + else + { + if (rd->rd_stream) + { + fflush(rd->rd_stream); + fclose(rd->rd_stream); + } + else if (rd->rd_fd >= 0 && rd->rd_fd != 1) + { + close(rd->rd_fd); + } + + rd->rd_fd = -1; + rd->rd_stream = NULL; + } +} + +/**************************************************************************** + * Name: nsh_putchar + * + * Description: + * Add another parsed character to the TELNET command string + * + * Assumption: + * Caller holds TIO semaphore + * + ****************************************************************************/ + +static void nsh_putchar(struct telnetd_s *pstate, uint8_t ch) +{ + struct telnetio_s *tio = pstate->u.tn; + + /* Ignore carriage returns */ + + if (ch == ISO_cr) + { + return; + } + + /* Add all other characters to the cmd buffer */ + + pstate->tn_cmd[tio->tio_bufndx] = ch; + + /* If a newline was added or if the buffer is full, then process it now */ + + if (ch == ISO_nl || tio->tio_bufndx == (CONFIG_NSH_LINELEN - 1)) + { + pstate->tn_cmd[tio->tio_bufndx] = '\0'; + nsh_telnetdump(&pstate->tn_vtbl, "TELNET CMD", + (uint8_t*)pstate->tn_cmd, strlen(pstate->tn_cmd)); + nsh_parse(&pstate->tn_vtbl, pstate->tn_cmd); + tio->tio_bufndx = 0; + } + else + { + tio->tio_bufndx++; + vdbg("Add '%c', bufndx=%d\n", ch, tio->tio_bufndx); + } +} + +/**************************************************************************** + * Name: nsh_sendopt + * + * Description: + * + ****************************************************************************/ + +static void nsh_sendopt(struct telnetd_s *pstate, uint8_t option, uint8_t value) +{ + struct telnetio_s *tio = pstate->u.tn; + uint8_t optbuf[4]; + optbuf[0] = TELNET_IAC; + optbuf[1] = option; + optbuf[2] = value; + optbuf[3] = 0; + + nsh_telnetdump(&pstate->tn_vtbl, "Send optbuf", optbuf, 4); + tio_semtake(tio); /* Only one call to send at a time */ + if (send(tio->tio_sockfd, optbuf, 4, 0) < 0) + { + dbg("[%d] Failed to send TELNET_IAC: %d\n", tio->tio_sockfd, errno); + } + tio_semgive(tio); +} + +/**************************************************************************** + * Name: nsh_flush + * + * Description: + * Dump the buffered output info. + * + ****************************************************************************/ + +static void nsh_flush(FAR struct telnetd_s *pstate) +{ + struct telnetio_s *tio = pstate->u.tn; + + if (pstate->tn_sndlen > 0) + { + nsh_telnetdump(&pstate->tn_vtbl, "Shell output", + (uint8_t*)pstate->tn_outbuffer, pstate->tn_sndlen); + tio_semtake(tio); /* Only one call to send at a time */ + if (send(tio->tio_sockfd, pstate->tn_outbuffer, pstate->tn_sndlen, 0) < 0) + { + dbg("[%d] Failed to send response: %d\n", tio->tio_sockfd, errno); + } + tio_semgive(tio); + } + pstate->tn_sndlen = 0; +} + +/**************************************************************************** + * Name: nsh_receive + * + * Description: + * Process a received TELENET buffer + * + ****************************************************************************/ + +static int nsh_receive(struct telnetd_s *pstate, size_t len) +{ + struct telnetio_s *tio = pstate->u.tn; + char *ptr = tio->tio_inbuffer; + uint8_t ch; + + while (len > 0) + { + ch = *ptr++; + len--; + + vdbg("ch=%02x state=%d\n", ch, tio->tio_state); + switch (tio->tio_state) + { + case STATE_IAC: + if (ch == TELNET_IAC) + { + nsh_putchar(pstate, ch); + tio->tio_state = STATE_NORMAL; + } + else + { + switch (ch) + { + case TELNET_WILL: + tio->tio_state = STATE_WILL; + break; + + case TELNET_WONT: + tio->tio_state = STATE_WONT; + break; + + case TELNET_DO: + tio->tio_state = STATE_DO; + break; + + case TELNET_DONT: + tio->tio_state = STATE_DONT; + break; + + default: + tio->tio_state = STATE_NORMAL; + break; + } + } + break; + + case STATE_WILL: + /* Reply with a DONT */ + + nsh_sendopt(pstate, TELNET_DONT, ch); + tio->tio_state = STATE_NORMAL; + break; + + case STATE_WONT: + /* Reply with a DONT */ + + nsh_sendopt(pstate, TELNET_DONT, ch); + tio->tio_state = STATE_NORMAL; + break; + + case STATE_DO: + /* Reply with a WONT */ + + nsh_sendopt(pstate, TELNET_WONT, ch); + tio->tio_state = STATE_NORMAL; + break; + + case STATE_DONT: + /* Reply with a WONT */ + + nsh_sendopt(pstate, TELNET_WONT, ch); + tio->tio_state = STATE_NORMAL; + break; + + case STATE_NORMAL: + if (ch == TELNET_IAC) + { + tio->tio_state = STATE_IAC; + } + else + { + nsh_putchar(pstate, ch); + } + break; + } + } + return OK; +} + +/**************************************************************************** + * Name: nsh_connection + * + * Description: + * Each time a new connection to port 23 is made, a new thread is created + * that begins at this entry point. There should be exactly one argument + * and it should be the socket descriptor (+1). + * + ****************************************************************************/ + +static void *nsh_connection(void *arg) +{ + struct telnetd_s *pstate = nsh_allocstruct(); + struct telnetio_s *tio = (struct telnetio_s *)zalloc(sizeof(struct telnetio_s)); + struct nsh_vtbl_s *vtbl = &pstate->tn_vtbl; + int sockfd = (int)arg; + int ret = ERROR; + + dbg("[%d] Started\n", sockfd); + + /* Verify that the state structure was successfully allocated */ + + if (pstate && tio) + { + /* Initialize the thread state structure */ + + sem_init(&tio->tio_sem, 0, 1); + tio->tio_sockfd = sockfd; + tio->tio_state = STATE_NORMAL; + pstate->u.tn = tio; + + /* Output a greeting */ + + nsh_output(vtbl, g_nshgreeting); + + /* Execute the startup script */ + +#if defined(CONFIG_NSH_ROMFSETC) && !defined(CONFIG_NSH_CONSOLE) + (void)nsh_script(vtbl, "init", NSH_INITPATH); +#endif + + /* Loop processing each TELNET command */ + + do + { + /* Display the prompt string */ + + nsh_output(vtbl, g_nshprompt); + nsh_flush(pstate); + + /* Read a buffer of data from the TELNET client */ + + ret = recv(tio->tio_sockfd, tio->tio_inbuffer, + CONFIG_NSH_IOBUFFER_SIZE, 0); + if (ret > 0) + { + + /* Process the received TELNET data */ + + nsh_telnetdump(vtbl, "Received buffer", + (uint8_t*)tio->tio_inbuffer, ret); + ret = nsh_receive(pstate, ret); + } + } + while (ret >= 0 && tio->tio_state != STATE_CLOSE); + dbg("[%d] ret=%d tn.tio_state=%d\n", sockfd, ret, tio->tio_state); + + /* End of command processing -- Clean up and exit */ + } + + /* Exit the task */ + + if (pstate) + { + free(pstate); + } + + if (tio) + { + sem_destroy(&tio->tio_sem); + free(tio); + } + + dbg("[%d] Exitting\n", sockfd); + close(sockfd); + return NULL; +} + +/**************************************************************************** + * Name: nsh_telnetwrite + * + * Description: + * write a buffer to the remote shell window. + * + * Currently only used by cat. + * + ****************************************************************************/ + +static ssize_t nsh_telnetwrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes) +{ + struct telnetd_s *pstate = (struct telnetd_s *)vtbl; + struct telnetio_s *tio = pstate->u.tn; + ssize_t ret = nbytes; + + /* Flush anything already in the output buffer */ + + nsh_flush(pstate); + + /* Then write the user buffer */ + + nsh_telnetdump(&pstate->tn_vtbl, "Buffer output",(uint8_t*)buffer, nbytes); + + tio_semtake(tio); /* Only one call to send at a time */ + ret = send(tio->tio_sockfd, buffer, nbytes, 0); + if (ret < 0) + { + dbg("[%d] Failed to send buffer: %d\n", tio->tio_sockfd, errno); + } + + tio_semgive(tio); + return ret; +} + +/**************************************************************************** + * Name: nsh_telnetoutput + * + * Description: + * Print a string to the remote shell window. + * + * This function is implemented by the shell GUI / telnet server and + * can be called by the shell back-end to output a string in the + * shell window. The string is automatically appended with a linebreak. + * + ****************************************************************************/ + +static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) +{ + struct telnetd_s *pstate = (struct telnetd_s *)vtbl; + int nbytes = pstate->tn_sndlen; + int len; + va_list ap; + + /* Put the new info into the buffer. Here we are counting on the fact that + * no output strings will exceed CONFIG_NSH_LINELEN! + */ + + va_start(ap, fmt); + vsnprintf(&pstate->tn_outbuffer[nbytes], + (CONFIG_NSH_IOBUFFER_SIZE - 1) - nbytes, fmt, ap); + va_end(ap); + + /* Get the size of the new string just added and the total size of + * buffered data + */ + + len = strlen(&pstate->tn_outbuffer[nbytes]); + nbytes += len; + + /* Expand any terminating \n to \r\n */ + + if (nbytes < (CONFIG_NSH_IOBUFFER_SIZE - 2) && + pstate->tn_outbuffer[nbytes-1] == '\n') + { + pstate->tn_outbuffer[nbytes-1] = ISO_cr; + pstate->tn_outbuffer[nbytes] = ISO_nl; + pstate->tn_outbuffer[nbytes+1] = '\0'; + nbytes++; + } + pstate->tn_sndlen = nbytes; + + /* Flush to the network if the buffer does not have room for one more + * maximum length string. + */ + + if (nbytes > CONFIG_NSH_IOBUFFER_SIZE - CONFIG_NSH_LINELEN) + { + nsh_flush(pstate); + } + + return len; +} + +/**************************************************************************** + * Name: nsh_redirectoutput + * + * Description: + * Print a string to the currently selected stream. + * + ****************************************************************************/ + +static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) +{ + FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; + va_list ap; + int ret; + + /* The stream is open in a lazy fashion. This is done because the file + * descriptor may be opened on a different task than the stream. The + * actual open will then occur with the first output from the new task. + */ + + if (nsh_openifnotopen(pstate) != 0) + { + return ERROR; + } + + va_start(ap, fmt); + ret = vfprintf(pstate->u.rd.rd_stream, fmt, ap); + va_end(ap); + + return ret; +} + +/**************************************************************************** + * Name: nsh_telnetlinebuffer + * + * Description: + * Return a reference to the current line buffer + * +* ****************************************************************************/ + +static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl) +{ + struct telnetd_s *pstate = (struct telnetd_s *)vtbl; + return pstate->tn_cmd; +} + +/**************************************************************************** + * Name: nsh_telnetclone + * + * Description: + * Make an independent copy of the vtbl + * + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; + FAR struct telnetd_s *pclone = nsh_allocstruct(); + FAR struct nsh_vtbl_s *ret = NULL; + + if (pclone) + { + if (pstate->tn_redirected) + { + pclone->tn_redirected = true; + pclone->tn_vtbl.output = nsh_redirectoutput; + pclone->u.rd.rd_fd = pstate->u.rd.rd_fd; + pclone->u.rd.rd_stream = NULL; + } + else + { + pclone->u.tn = pstate->u.tn; + } + ret = &pclone->tn_vtbl; + } + return ret; +} +#endif + +/**************************************************************************** + * Name: nsh_telnetrelease + * + * Description: + * Release the cloned instance + * + ****************************************************************************/ + +#ifndef CONFIG_NSH_DISABLEBG +static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl) +{ + FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; + + if (pstate->tn_redirected) + { + nsh_closeifnotclosed(pstate); + } + else + { + nsh_flush(pstate); + } + free(pstate); +} +#endif + +/**************************************************************************** + * Name: nsh_telnetredirect + * + * Description: + * Set up for redirected output. This function is called from nsh_parse() + * in two different contexts: + * + * 1) Redirected background commands of the form: command > xyz.text & + * + * In this case: + * - vtbl: A newly allocated and initialized instance created by + * nsh_telnetclone, + * - fd:- The file descriptor of the redirected output + * - save: NULL + * + * nsh_telnetrelease() will perform the clean-up when the clone is + * destroyed. + * + * 2) Redirected foreground commands of the form: command > xyz.txt + * + * In this case: + * - vtbl: The current state structure, + * - fd: The file descriptor of the redirected output + * - save: Where to save the re-directed registers. + * + * nsh_telnetundirect() will perform the clean-up after the redirected + * command completes. + * + ****************************************************************************/ + +static void nsh_telnetredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save) +{ + FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; + FAR struct telnetsave_s *ssave = (FAR struct telnetsave_s *)save; + + if (pstate->tn_redirected) + { + (void)nsh_openifnotopen(pstate); + fflush(pstate->u.rd.rd_stream); + if (!ssave) + { + fclose(pstate->u.rd.rd_stream); + } + } + + if (ssave) + { + ssave->ts_redirected = pstate->tn_redirected; + memcpy(&ssave->u.rd, &pstate->u.rd, sizeof(struct redirect_s)); + } + + pstate->tn_redirected = true; + pstate->u.rd.rd_fd = fd; + pstate->u.rd.rd_stream = NULL; +} + +/**************************************************************************** + * Name: nsh_telnetundirect + * + * Description: + * Set up for redirected output + * + ****************************************************************************/ + +static void nsh_telnetundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save) +{ + FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; + FAR struct telnetsave_s *ssave = (FAR struct telnetsave_s *)save; + + if (pstate->tn_redirected) + { + nsh_closeifnotclosed(pstate); + } + + pstate->tn_redirected = ssave->ts_redirected; + memcpy(&pstate->u.rd, &ssave->u.rd, sizeof(struct redirect_s)); +} + +/**************************************************************************** + * Name: nsh_telnetexit + * + * Description: + * Quit the shell instance + * + ****************************************************************************/ + +static void nsh_telnetexit(FAR struct nsh_vtbl_s *vtbl) +{ + struct telnetd_s *pstate = (struct telnetd_s *)vtbl; + pstate->u.tn->tio_state = STATE_CLOSE; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_telnetmain + * + * Description: + * This is the main processing thread for telnetd. It never returns + * unless an error occurs + * + ****************************************************************************/ + +int nsh_telnetmain(int argc, char *argv[]) +{ + /* Execute nsh_connection() on each connection to port 23 */ + + uip_server(HTONS(23), nsh_connection, CONFIG_NSH_STACKSIZE); + return OK; +} + +#endif /* CONFIG_NSH_TELNET */ diff --git a/apps/nshlib/nsh_test.c b/apps/nshlib/nsh_test.c new file mode 100644 index 000000000..dd63d6796 --- /dev/null +++ b/apps/nshlib/nsh_test.c @@ -0,0 +1,437 @@ +/**************************************************************************** + * apps/nshlib/nsh_test.c + * + * Copyright (C) 2008, 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* Test syntax: + * + * expression = simple-expression | !expression | + * expression -o expression | expression -a expression + * + * simple-expression = unary-expression | binary-expression + * + * unary-expression = string-unary | file-unary + * + * string-unary = -n string | -z string + * + * file-unary = -b file | -c file | -d file | -e file | -f file | + * -r file | -s file | -w file + * + * binary-expression = string-binary | numeric-binary + * + * string-binary = string = string | string == string | string != string + * + * numeric-binary = integer -eq integer | integer -ge integer | + * integer -gt integer | integer -le integer | + * integer -lt integer | integer -ne integer + * + * Note that the smallest expression consists of two strings. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/stat.h> +#include <stdlib.h> +#include <string.h> + +#include "nsh.h" + +#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_TEST) + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define TEST_TRUE OK +#define TEST_FALSE ERROR +#define TEST_ERROR 1 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: binaryexpression + ****************************************************************************/ + +static inline int binaryexpression(FAR struct nsh_vtbl_s *vtbl, char **argv) +{ + char *endptr; + long integer1; + long integer2; + + /* STRING2 = STRING2 */ + + if (strcmp(argv[1], "=") == 0 || strcmp(argv[1], "==") == 0) + { + /* Return true if the strings are identical */ + + return strcmp(argv[0], argv[2]) == 0 ? TEST_TRUE : TEST_FALSE; + } + + /* STRING1 != STRING2 */ + + if (strcmp(argv[1], "!=") == 0) + { + /* Return true if the strings are different */ + + return strcmp(argv[0], argv[2]) != 0 ? TEST_TRUE : TEST_FALSE; + } + + /* The remaining operators assuming that the two values are integers */ + + integer1 = strtol(argv[0], &endptr, 0); + if (argv[0][0] == '\0' || *endptr != '\0') + { + return TEST_ERROR; + } + + integer2 = strtol(argv[2], &endptr, 0); + if (argv[2][0] == '\0' || *endptr != '\0') + { + return TEST_ERROR; + } + + /* INTEGER1 -eq INTEGER2 */ + + if (strcmp(argv[1], "-eq") == 0) + { + /* Return true if the strings are different */ + + return integer1 == integer2 ? TEST_TRUE : TEST_FALSE; + } + + /* INTEGER1 -ge INTEGER2 */ + + if (strcmp(argv[1], "-ge") == 0) + { + /* Return true if the strings are different */ + + return integer1 >= integer2 ? TEST_TRUE : TEST_FALSE; + } + + /* INTEGER1 -gt INTEGER2 */ + + if (strcmp(argv[1], "-gt") == 0) + { + /* Return true if the strings are different */ + + return integer1 > integer2 ? TEST_TRUE : TEST_FALSE; + } + + /* INTEGER1 -le INTEGER2 */ + + if (strcmp(argv[1], "-le") == 0) + { + /* Return true if the strings are different */ + + return integer1 <= integer2 ? TEST_TRUE : TEST_FALSE; + } + + /* INTEGER1 -lt INTEGER2 */ + + if (strcmp(argv[1], "-lt") == 0) + { + /* Return true if the strings are different */ + + return integer1 < integer2 ? TEST_TRUE : TEST_FALSE; + } + + /* INTEGER1 -ne INTEGER2 */ + + if (strcmp(argv[1], "-ne") == 0) + { + /* Return true if the strings are different */ + + return integer1 != integer2 ? TEST_TRUE : TEST_FALSE; + } + + return TEST_ERROR; +} + +/**************************************************************************** + * Name: unaryexpression + ****************************************************************************/ + +static inline int unaryexpression(FAR struct nsh_vtbl_s *vtbl, char **argv) +{ + struct stat buf; + char *fullpath; + int ret; + + /* -n STRING */ + + if (strcmp(argv[0], "-n") == 0) + { + /* Return true if the length of the string is non-zero */ + + return strlen(argv[1]) != 0 ? TEST_TRUE : TEST_FALSE; + } + + /* -z STRING */ + + if (strcmp(argv[0], "-z") == 0) + { + /* Return true if the length of the string is zero */ + + return strlen(argv[1]) == 0 ? TEST_TRUE : TEST_FALSE; + } + + /* All of the remaining assume that the following argument is the + * path to a file. + */ + + fullpath = nsh_getfullpath(vtbl, argv[1]); + if (!fullpath) + { + return TEST_FALSE; + } + + ret = stat(fullpath, &buf); + nsh_freefullpath(fullpath); + + if (ret != 0) + { + /* The file does not exist (or another error occurred) -- return FALSE */ + + return TEST_FALSE; + } + + /* -b FILE */ + + if (strcmp(argv[0], "-b") == 0) + { + /* Return true if the path is a block device */ + + return S_ISBLK(buf.st_mode) ? TEST_TRUE : TEST_FALSE; + } + + /* -c FILE */ + + if (strcmp(argv[0], "-c") == 0) + { + /* Return true if the path is a character device */ + + return S_ISCHR(buf.st_mode) ? TEST_TRUE : TEST_FALSE; + } + + /* -d FILE */ + + if (strcmp(argv[0], "-d") == 0) + { + /* Return true if the path is a directory */ + + return S_ISDIR(buf.st_mode) ? TEST_TRUE : TEST_FALSE; + } + + /* -e FILE */ + + if (strcmp(argv[0], "-e") == 0) + { + /* Return true if the file exists */ + + return TEST_TRUE; + } + + /* -f FILE */ + + if (strcmp(argv[0], "-f") == 0) + { + /* Return true if the path refers to a regular file */ + + return S_ISREG(buf.st_mode) ? TEST_TRUE : TEST_FALSE; + } + + /* -r FILE */ + + if (strcmp(argv[0], "-r") == 0) + { + /* Return true if the file is readable */ + + return (buf.st_mode & (S_IRUSR|S_IRGRP|S_IROTH)) != 0 ? TEST_TRUE : TEST_FALSE; + } + + /* -s FILE */ + + if (strcmp(argv[0], "-s") == 0) + { + /* Return true if the size of the file is greater than zero */ + + return buf.st_size > 0 ? TEST_TRUE : TEST_FALSE; + } + + /* -w FILE */ + + if (strcmp(argv[0], "-w") == 0) + { + /* Return true if the file is write-able */ + + return (buf.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0 ? TEST_TRUE : TEST_FALSE; + } + + /* Unrecognized operator */ + + return TEST_ERROR; +} + +/**************************************************************************** + * Name: expression + ****************************************************************************/ + +static int expression(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + int value; + int i = 0; + + /* Check for unary operations on expressions */ + + if (strcmp(argv[0], "!") == 0) + { + if (argc < 2) + { + goto errout_syntax; + } + return expression(vtbl, argc-1, &argv[1]) == TEST_TRUE ? TEST_FALSE : TEST_TRUE; + } + + /* Check for unary operations on simple, typed arguments */ + + else if (argv[0][0] == '-') + { + if (argc < 2) + { + goto errout_syntax; + } + i += 2; + value = unaryexpression(vtbl, argv); + } + + /* Check for binary operations on simple, typed arguments */ + + else + { + if (argc < 3) + { + goto errout_syntax; + } + i += 3; + value = binaryexpression(vtbl, argv); + } + + /* Test if there any failure */ + + if (value == TEST_ERROR) + { + goto errout_syntax; + } + + /* Is there anything after the simple expression? */ + + if (i < argc) + { + /* EXPRESSION -a EXPRESSION */ + + if (strcmp(argv[i], "-a") == 0) + { + if (value != TEST_TRUE) + { + return TEST_FALSE; + } + else + { + i++; + return expression(vtbl, argc-i, &argv[i]); + } + } + + /* EXPRESSION -o EXPRESSION */ + + else if (strcmp(argv[i], "-o") == 0) + { + if (value == TEST_TRUE) + { + return TEST_TRUE; + } + else + { + i++; + return expression(vtbl, argc-i, &argv[i]); + } + } + else + { + goto errout_syntax; + } + } + return value; + +errout_syntax: + nsh_output(vtbl, g_nshsyntax, "test"); + return TEST_FALSE; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_test + ****************************************************************************/ + +int cmd_test(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + return expression(vtbl, argc-1, &argv[1]); +} + +/**************************************************************************** + * Name: cmd_lbracket + ****************************************************************************/ + +int cmd_lbracket(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + if (strcmp(argv[argc-1], "]") != 0) + { + nsh_output(vtbl, g_nshsyntax, argv[0]); + return ERROR; + } + else + { + return expression(vtbl, argc-2, &argv[1]); + } +} + +#endif /* !CONFIG_NSH_DISABLESCRIPT && !CONFIG_NSH_DISABLE_TEST */ diff --git a/apps/nshlib/nsh_timcmds.c b/apps/nshlib/nsh_timcmds.c new file mode 100644 index 000000000..04a79e77d --- /dev/null +++ b/apps/nshlib/nsh_timcmds.c @@ -0,0 +1,330 @@ +/**************************************************************************** + * apps/nshlib/dbg_timcmds.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> + +#include "nsh.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define MAX_TIME_STRING 80 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +static FAR const char * const g_datemontab[] = +{ + "jan", "feb", "mar", "apr", "may", "jun", + "jul", "aug", "sep", "oct", "nov", "dec" +}; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: date_month + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +static inline int date_month(FAR const char *abbrev) +{ + int i; + + for (i = 0; i < 12; i++) + { + if (strncasecmp(g_datemontab[i], abbrev, 3) == 0) + { + return i; + } + } + return ERROR; +} +#endif + +/**************************************************************************** + * Name: date_gettime + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +static inline int date_showtime(FAR struct nsh_vtbl_s *vtbl, FAR const char *name) +{ + static const char format[] = "%b %d %H:%M:%S %Y"; + struct timespec ts; + struct tm tm; + char timbuf[MAX_TIME_STRING]; + int ret; + + /* Get the current time */ + + ret = clock_gettime(CLOCK_REALTIME, &ts); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, name, "clock_gettime", NSH_ERRNO); + return ERROR; + } + + /* Break the current time up into the format needed by strftime */ + + (void)gmtime_r((FAR const time_t*)&ts.tv_sec, &tm); + + /* Show the current time in the requested format */ + + (void)strftime(timbuf, MAX_TIME_STRING, format, &tm); + nsh_output(vtbl, "%s\n", timbuf); + return OK; +} +#endif + +/**************************************************************************** + * Name: date_settime + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +static inline int date_settime(FAR struct nsh_vtbl_s *vtbl, FAR const char *name, + FAR char *newtime) +{ + struct timespec ts; + struct tm tm; + FAR char *token; + FAR char *saveptr; + long result; + int ret; + + /* Only this date format is supported: MMM DD HH:MM:SS YYYY */ + /* Get the month abbreviation */ + + token = strtok_r(newtime, " \t",&saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + tm.tm_mon = date_month(token); + if (tm.tm_mon < 0) + { + goto errout_bad_parm; + } + + /* Get the day of the month. NOTE: Accepts day-of-month up to 31 for all months */ + + token = strtok_r(NULL, " \t",&saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 1 || result > 31) + { + goto errout_bad_parm; + } + tm.tm_mday = (int)result; + + /* Get the hours */ + + token = strtok_r(NULL, " \t:", &saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 0 || result > 23) + { + goto errout_bad_parm; + } + tm.tm_hour = (int)result; + + /* Get the minutes */ + + token = strtok_r(NULL, " \t:", &saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 0 || result > 59) + { + goto errout_bad_parm; + } + tm.tm_min = (int)result; + + /* Get the seconds */ + + token = strtok_r(NULL, " \t:", &saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 0 || result > 61) + { + goto errout_bad_parm; + } + tm.tm_sec = (int)result; + + /* And finally the year */ + + token = strtok_r(NULL, " \t", &saveptr); + if (token == NULL) + { + goto errout_bad_parm; + } + + result = strtol(token, NULL, 10); + if (result < 1900 || result > 2100) + { + goto errout_bad_parm; + } + tm.tm_year = (int)result - 1900; + + /* Convert this to the right form, then set the timer */ + + ts.tv_sec = mktime(&tm); + ts.tv_nsec = 0; + + ret = clock_settime(CLOCK_REALTIME, &ts); + if (ret < 0) + { + nsh_output(vtbl, g_fmtcmdfailed, name, "clock_settime", NSH_ERRNO); + return ERROR; + } + return OK; + +errout_bad_parm: + nsh_output(vtbl, g_fmtarginvalid, name); + return ERROR; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_date + ****************************************************************************/ + +#if defined (CONFIG_RTC) && !defined(CONFIG_DISABLE_CLOCK) && !defined(CONFIG_NSH_DISABLE_DATE) +int cmd_date(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) +{ + FAR char *newtime = NULL; + FAR const char *errfmt; + bool badarg = false; + int option; + int ret; + + /* Get the date options: date [-s time] [+FORMAT] */ + + while ((option = getopt(argc, argv, "s:")) != ERROR) + { + if (option == 's') + { + /* We will be setting the time */ + + newtime = optarg; + } + else /* option = '?' */ + { + /* We need to parse to the end anyway so that getopt stays healthy */ + + badarg = true; + } + } + + /* If a bad argument was encountered then exit with an error */ + + if (badarg) + { + errfmt = g_fmtarginvalid; + goto errout; + } + + /* optind < argc-1 means that there are additional, unexpected arguments on + * th command-line + */ + + if (optind < argc) + { + errfmt = g_fmttoomanyargs; + goto errout; + } + + /* Display or set the time */ + + if (newtime) + { + ret = date_settime(vtbl, argv[0], newtime); + } + else + { + ret = date_showtime(vtbl, argv[0]); + } + return ret; + +errout: + nsh_output(vtbl, errfmt, argv[0]); + return ERROR; +} +#endif diff --git a/apps/nshlib/rcS.template b/apps/nshlib/rcS.template new file mode 100644 index 000000000..996f37fb1 --- /dev/null +++ b/apps/nshlib/rcS.template @@ -0,0 +1,5 @@ +# Create a RAMDISK and mount it at XXXRDMOUNTPOUNTXXX + +mkrd -m XXXMKRDMINORXXX -s XXMKRDSECTORSIZEXXX XXMKRDBLOCKSXXX +mkfatfs /dev/ramXXXMKRDMINORXXX +mount -t vfat /dev/ramXXXMKRDMINORXXX XXXRDMOUNTPOUNTXXX diff --git a/apps/system/Makefile b/apps/system/Makefile new file mode 100644 index 000000000..3697f4aa4 --- /dev/null +++ b/apps/system/Makefile @@ -0,0 +1,70 @@ +############################################################################ +# apps/system/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration + +# Sub-directories containing system task + +SUBDIRS = free i2c install + +# Create the list of installed runtime modules (INSTALLED_DIRS) + +define ADD_DIRECTORY +INSTALLED_DIRS += ${shell if [ -r $1/Makefile ]; then echo "$1"; fi} +endef + +$(foreach DIR, $(SUBDIRS), $(eval $(call ADD_DIRECTORY,$(DIR)))) + +all: nothing +.PHONY: nothing context depend clean distclean + +nothing: + +context: + +depend: + @for dir in $(INSTALLED_DIRS) ; do \ + $(MAKE) -C $$dir depend TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +clean: + @for dir in $(INSTALLED_DIRS) ; do \ + $(MAKE) -C $$dir clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +distclean: clean + @for dir in $(INSTALLED_DIRS) ; do \ + $(MAKE) -C $$dir distclean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done diff --git a/apps/system/free/Makefile b/apps/system/free/Makefile new file mode 100644 index 000000000..51bd9a6e3 --- /dev/null +++ b/apps/system/free/Makefile @@ -0,0 +1,110 @@ +############################################################################ +# apps/system/free/Makefile +# +# Copyright (C) 2011 Uros Platise. All rights reserved. +# Author: Uros Platise <uros.platise@isotel.eu> +# Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TODO, this makefile should run make under the app dirs, instead of +# sourcing the Make.defs! + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +# Hello Application +# TODO: appname can be automatically extracted from the directory name + +APPNAME = free +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 768 + +ASRCS = +CSRCS = free.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +BIN = $(APPDIR)/libapps$(LIBEXT) + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +# Register application + +.context: + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ + +context: .context + +# Create dependencies + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f .context Make.dep .depend + +-include Make.dep diff --git a/apps/system/free/README.txt b/apps/system/free/README.txt new file mode 100644 index 000000000..dd92a94ae --- /dev/null +++ b/apps/system/free/README.txt @@ -0,0 +1,6 @@ + +This application provides UNIX style memory free information. + + Source: NuttX + Author: Gregory Nutt <spudmonkey@racsa.co.cr> + Date: 17. March 2011 diff --git a/apps/system/free/free.c b/apps/system/free/free.c new file mode 100644 index 000000000..2f61a1dae --- /dev/null +++ b/apps/system/free/free.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * apps/system/free/free.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/progmem.h> + +#include <stdio.h> +#include <stdlib.h> + + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* \todo Max block size only works on uniform prog mem */ + +void free_getprogmeminfo(struct mallinfo * mem) +{ + uint16_t page = 0, stpage = 0xFFFF; + uint16_t pagesize = 0; + int status; + + mem->arena = 0; + mem->fordblks = 0; + mem->uordblks = 0; + mem->mxordblk = 0; + + for (status=0, page=0; status >= 0; page++) { + + status = up_progmem_ispageerased(page); + pagesize = up_progmem_pagesize(page); + + mem->arena += pagesize; + + /* Is this beginning of new free space section */ + if (status == 0) { + if (stpage == 0xFFFF) stpage = page; + mem->fordblks += pagesize; + } + else if (status != 0) { + mem->uordblks += pagesize; + + if (stpage != 0xFFFF && up_progmem_isuniform()) { + stpage = page - stpage; + if (stpage > mem->mxordblk) + mem->mxordblk = stpage; + stpage = 0xFFFF; + } + } + } + + mem->mxordblk *= pagesize; +} + + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int free_main(int argc, char **argv) +{ + struct mallinfo data; + struct mallinfo prog; + +#ifdef CONFIG_CAN_PASS_STRUCTS + data = mallinfo(); +#else + (void)mallinfo(&data); +#endif + + free_getprogmeminfo(&prog); + + printf(" total used free largest\n"); + printf("Data: %11d%11d%11d%11d\n", + data.arena, data.uordblks, data.fordblks, data.mxordblk); + printf("Prog: %11d%11d%11d%11d\n", + prog.arena, prog.uordblks, prog.fordblks, prog.mxordblk); + + return OK; +} diff --git a/apps/system/i2c/Makefile b/apps/system/i2c/Makefile new file mode 100644 index 000000000..5ea974452 --- /dev/null +++ b/apps/system/i2c/Makefile @@ -0,0 +1,103 @@ +############################################################################ +# apps/system/i2c +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# I2C tool + +ASRCS = +CSRCS = i2c_bus.c i2c_common.c i2c_dev.c i2c_get.c i2c_main.c i2c_set.c i2c_verf.c + + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . +VPATH = + +APPNAME = i2c +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +# Build targets + +all: .built +.PHONY: .context context .depend depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +.context: + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ + +context: .context + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) \ + $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep + diff --git a/apps/system/i2c/README.txt b/apps/system/i2c/README.txt new file mode 100755 index 000000000..97801bcaa --- /dev/null +++ b/apps/system/i2c/README.txt @@ -0,0 +1,397 @@ +README File for the I2C Tool
+============================
+
+The I2C tool provides a way to debug I2C related problems. This README file
+will provide usage information for the I2C tools.
+
+CONTENTS
+========
+
+ o System Requirements
+ - I2C Driver
+ - Configuration Options
+ o Help
+ o Common Line Form
+ o Common Command Options
+ - "Sticky" Options
+ - Environment variables
+ - Common Option Summary
+ o Command summary
+ - bus
+ - dev
+ - get
+ - set
+ - verf
+ o I2C Build Configuration
+ - NuttX Configuration Requirements
+ - I2C Tool Configuration Options
+
+System Requirements
+===================
+
+I2C Driver
+----------
+In order to use the I2C driver, you system -- in particular, your I2C driver --
+must meet certain requirements:
+
+1. It support calling up_i2cinitialize() numerous times, resetting the I2C
+ hardware on each (initial) time. up_i2cuninitialize() will be called after
+ each call to up_i2cinitialize() to free any resources and disable the I2C.
+2. up_i2cinitialize must accept any interface number without crashing. It
+ must simply return NULL if the device is not supported.
+3. The I2C driver must support the transfer method (CONFIG_I2C_TRANSFER=y).
+
+The I2C tool is designed to be implemented as a NuttShell (NSH) add-on. Read
+the apps/nshlib/README.txt file for information about add-ons.
+
+Configuration Options
+---------------------
+CONFIG_I2CTOOL_BUILTIN - Build the tools as an NSH built-in command
+CONFIG_I2CTOOL_MINBUS - Smallest bus index supported by the hardware (default 0).
+CONFIG_I2CTOOL_MAXBUS - Largest bus index supported by the hardware (default 3)
+CONFIG_I2CTOOL_MINADDR - Minium device address (default: 0x03)
+CONFIG_I2CTOOL_MAXADDR - Largest device address (default: 0x77)
+CONFIG_I2CTOOL_MAXREGADDR - Largest register address (default: 0xff)
+CONFIG_I2CTOOL_DEFFREQ - Default frequency (default: 4000000)
+
+HELP
+====
+
+First of all, the I2C tools supports a pretty extensive help output. That
+help output can be view by entering either:
+
+ nsh> i2c help
+
+or
+
+ nsh> i2c ?
+
+Here is an example of the help output. I shows the general form of the
+command line, the various I2C commands supported with their unique command
+line options, and a more detailed summary of the command I2C command
+options.
+
+ nsh> i2c help
+ Usage: i2c <cmd> [arguments]
+ Where <cmd> is one of:
+
+ Show help : ?
+ List buses : bus
+ List devices : dev [OPTIONS] <first> <last>
+ Read register : get [OPTIONS] [<repititions>]
+ Show help : help
+ Write register: set [OPTIONS] <value> [<repititions>]
+ Verify access : verf [OPTIONS] <value> [<repititions>]
+
+ Where common "sticky" OPTIONS include:
+ [-a addr] is the I2C device address (hex). Default: 03 Current: 03
+ [-b bus] is the I2C bus number (decimal). Default: 1 Current: 1
+ [-r regaddr] is the I2C device register address (hex). Default: 00 Current: 00
+ [-w width] is the data width (8 or 16 decimal). Default: 8 Current: 8
+ [-s|n], send/don't send start between command and data. Default: -n Current: -n
+ [-i|j], Auto increment|don't increment regaddr on repititions. Default: NO Current: NO
+ [-f freq] I2C frequency. Default: 100000 Current: 100000
+
+ NOTES:
+ o An environment variable like $PATH may be used for any argument.
+ o Arguments are "sticky". For example, once the I2C address is
+ specified, that address will be re-used until it is changed.
+
+ WARNING:
+ o The I2C dev command may have bad side effects on your I2C devices.
+ Use only at your own risk.
+
+COMMAND LINE FORM
+=================
+
+The I2C is started from NSH by invoking the 'i2c' command from the NSH
+command line. The general form of the 'i2c' command is:
+
+ i2c <cmd> [arguments]
+
+Where <cmd> is a "sub-command" and identifies one I2C operations supported
+by the tool. [arguments] represents the list of arguments needed to perform
+the I2C operation. Those arguments vary from command to command as
+described below. However, there is also a core set of common OPTIONS
+supported by all commands. So perhaps a better representation of the
+general I2C command would be:
+
+ i2c <cmd> [OPTIONS] [arguments]
+
+Where [OPTIONS] represents the common options and and arguments represent
+the operation-specific arguments.
+
+COMMON COMMAND OPTIONS
+======================
+
+"Sticky" Options
+----------------
+In order to interact with I2C devices, there are a number of I2C parameters
+that must be set correctly. One way to do this would be to provide to set
+the value of each separate command for each I2C parameter. The I2C tool
+takes a different approach, instead: The I2C configuration can be specified
+as a (potentially long) sequence of command line arguments.
+
+These arguments, however, are "sticky." They are sticky in the sense that
+once you set the I2C parameter, that value will remain until it is reset
+with a new value (or until you reset the board).
+
+Environment Variables
+---------------------
+NOTE also that if environment variables are not disabled (by
+CONFIG_DISABLE_ENVIRON=y), then these options may also be environment
+variables. Environment variables must be preceded with the special
+character $. For example, PWD is the variable that holds the current
+working directory and so $PWD could be used as a command line argument. The
+use of environment variables on the I2C tools command is really only useful
+if you wish to write NSH scripts to execute a longer, more complex series of
+I2C commands.
+
+Common Option Summary
+---------------------
+
+[-a addr] is the I2C device address (hex). Default: 03 Current: 03
+
+ The [-a addr] sets the I2C device address. The valid range is 0x03
+ through 0x77 (this valid range is controlled by the configuration settings
+ CONFIG_I2CTOOL_MINADDR and CONFIG_I2CTOOL_MAXADDR). If you are working
+ with the same device, the address needs to be set only once.
+
+ All I2C address are 7-bit, hexadecimal values.
+
+ NOTE 1: Notice in the "help" output above it shows both default value of
+ the I2C address (03 hex) and the current address value (also 03 hex).
+
+ NOTE 2: Sometimes I2C addresses are represented as 8-bit values (with
+ bit zero indicating a read or write operation). The I2C tool uses a
+ 7-bit representation of the address with bit 7 unused and no read/write
+ indication in bit 0. Essentially, the 7-bit address is like the 8-bit
+ address shifted right by 1.
+
+ NOTE 3: Most I2C bus controllers will also support 10-bit addressing.
+ That capability has not been integrated into the I2C tool as of this
+ writing.
+
+[-b bus] is the I2C bus number (decimal). Default: 1 Current: 1
+
+ Most devices support multiple I2C devices and also have unique bus
+ numbering. This option identifies which bus you are working with now.
+ The valid range of bus numbers is controlled by the configuration settings
+ CONFIG_I2CTOOL_MINBUS and CONFIG_I2CTOOL_MAXBUS.
+
+ The bus numbers are small, decimal numbers.
+
+[-r regaddr] is the I2C device register address (hex). Default: 00 Current: 00
+
+ The I2C set and get commands will access registers on the I2C device. This
+ option selects the device register address (sometimes called the sub-address).
+ This is an 8-bit hexadecimal value. The maximum value is determined by
+ the configuration setting CONFIG_I2CTOOL_MAXREGADDR.
+
+[-w width] is the data width (8 or 16 decimal). Default: 8 Current: 8
+
+ Device register data may be 8-bit or 16-bit. This options selects one of
+ those two data widths.
+
+[-s|n], send/don't send start between command and data. Default: -n Current: -n
+
+ This determines whether or not there should be a new I2C START between
+ sending of the register address and sending/receiving of the register data.
+
+[-i|j], Auto increment|don't increment regaddr on repititions. Default: NO Current: NO
+
+ On commands that take a optional number of repetitions, the option can be
+ used to temporarily increment the regaddr value by one on each repitition.
+
+[-f freq] I2C frequency. Default: 400000 Current: 400000
+
+ The [-f freq] sets the frequency of the I2C device.
+
+COMMAND SUMMARY
+===============
+
+We have already seen the I2C help (or ?) commands above. This section will
+discusse the remaining commands.
+
+List buses: bus [OPTIONS]
+--------------------------
+
+This command will simply list all of the configured I2C buses and indicate
+which are supported by the driver and which are not:
+
+ BUS EXISTS?
+ Bus 1: YES
+ Bus 2: NO
+
+The valid range of bus numbers is controlled by the configuration settings
+CONFIG_I2CTOOL_MINBUS and CONFIG_I2CTOOL_MAXBUS.
+
+List devices: dev [OPTIONS] <first> <last>
+------------------------------------------
+
+The 'dev' command will attempt to identify all of the I2C devices on the
+selected bus. The <first> and <last> arguments are 7-bit, hexadecimal
+I2C addresses. This command will examine a range of addresses beginning
+with <first> and continuing through <last>. It will request the value
+of register zero from each device.
+
+If the device at an address responds, then this command will display the
+address of the device. If the device does not respond, this command will
+display "--". The resulting display is like:
+
+nsh> i2c dev 03 77
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f
+00: -- -- -- -- -- -- -- -- -- -- -- -- --
+10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+40: -- -- -- -- -- -- -- -- -- 49 -- -- -- -- -- --
+50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+70: -- -- -- -- -- -- -- --
+
+WARNINGS:
+ o The I2C dev command may have bad side effects on certain I2C devices.
+ For example, if could cause data loss in an EEPROM device.
+ o The I2C dev command also depends upon the underlying behavior of the
+ I2C driver. How does the driver respond to addressing failures?
+
+Read register: get [OPTIONS]
+----------------------------
+
+ This command will read the value of the I2C register using the selected
+ I2C parameters in the common options. No other arguments are required.
+
+ This command with write the 8-bit address value then read an 8- or 16-bit
+ data value from the device. Optionally, it may re-start the transfer
+ before obtaining the data.
+
+ An optional <repititions> argument can be supplied to repeat the
+ read operation an arbitrary number of times (up to 2 billion). If
+ auto-increment is select (-i), then the register address will be
+ temporarily incremented on each repitions. The increment is temporary
+ in the since that it will not alter the "sticky" value of the
+ register address.
+
+ On success, the output will look like the following (the data value
+ read will be shown as a 4-character hexadecimal number if the 16-bit
+ data width option is selected).
+
+ READ Bus: 1 Addr: 49 Subaddr: 04 Value: 96
+
+ All values (except the bus numbers) are hexadecimal.
+
+Write register: set [OPTIONS] <value>
+-------------------------------------
+
+ This command will write a value to an I2C register using the selected
+ I2C parameters in the common options. The value to write must be provided
+ as the final, hexadecimal value. This value may be an 8-bit value (in the
+ range 00-ff) or a 16-bit value (in the range 0000-ffff), depending upon
+ the selected data width.
+
+ This command will write the 8-bit address value then write the 8- or 16-bit
+ data value to the device. Optionally, it may re-start the transfer
+ before writing the data.
+
+ An optional <repititions> argument can be supplied to repeat the
+ write operation an arbitrary number of times (up to 2 billion). If
+ auto-increment is select (-i), then the register address will be
+ temporarily incremented on each repitions. The increment is temporary
+ in the since that it will not alter the "sticky" value of the
+ register address.
+
+ On success, the output will look like the following (the data value
+ written will be shown as a 4-character hexadecimal number if the 16-bit
+ data width option is selected).
+
+ WROTE Bus: 1 Addr: 49 Subaddr: 04 Value: 96
+
+ All values (except the bus numbers) are hexadecimal.
+
+Verify access : verf [OPTIONS] <value> [<repititions>]
+------------------------------------------------------
+
+ This command combines writing and reading from an I2C device register.
+ It will write a value to an will write a value to an I2C register using
+ the selected I2C parameters in the common options just as described for
+ tie 'set' command. Then this command will read the value back just
+ as described with the 'get' command. Finally, this command will compare
+ the value read and against the value written and emit an error message
+ if they do not match.
+
+ If no value is provided, then this command will use the register address
+ itself as the data, providing for a address-in-address test.
+
+ An optional <repititions> argument can be supplied to repeat the
+ verify operation an arbitrary number of times (up to 2 billion). If
+ auto-increment is select (-i), then the register address will be
+ temporarily incremented on each repitions. The increment is temporary
+ in the since that it will not alter the "sticky" value of the
+ register address.
+
+ On success, the output will look like the following (the data value
+ written will be shown as a 4-character hexadecimal number if the 16-bit
+ data width option is selected).
+
+ VERIFY Bus: 1 Addr: 49 Subaddr: 04 Wrote: 96 Read: 92 FAILURE
+
+ All values (except the bus numbers) are hexadecimal.
+
+I2C BUILD CONFIGURATION
+=======================
+
+NuttX Configuration Requirements
+--------------------------------
+The I2C tools requires the following in your NuttX configuration:
+
+1. Device-specific I2C support must be enabled. The I2C tool will call the
+ platform-specific function up_i2cinitialize() to get instances of the
+ I2C interface and the platform-specific function up_i2cuninitialize()
+ to discard instances of the I2C interface.
+
+ NOTE 1: The I2C interface is defined in include/nuttx/i2c.h.
+
+ NOTE 2: This I2C tool uses direct I2C device interfaces. As such, it
+ relies on internal OS interfaces that are not normally available to a
+ user-space program. As a result, the I2C tool cannot be used if a
+ NuttX is built as a protected, supervisor kernel (CONFIG_NUTTX_KERNEL).
+
+2. I2C driver configuration
+
+ The CONFIG_I2C_TRANSFER option must also be set in your NuttX
+ configuration. This configuration is the defconfig file in your
+ configuration directory that is copied to the NuttX top-level
+ directory as .config when NuttX is configured.
+
+ CONFIG_I2C_TRANSFER=y
+
+ NOTE: CONFIG_I2C_TRANSFER adds extra methods to the I2C interface.
+ Not all I2C interfaces support these extra methods. If your platform's
+ I2C driver does not support these extra methods, then you cannot use
+ the I2C tool unless you extend the support in your platform I2C
+ driver.
+
+3. Application configuration.
+
+ The path to the I2C tool directory must also be set in your NuttX
+ application configuration. This application configuration is the
+ appconfig file in your configuration directory that is copied to the
+ NuttX application directory as .config when NuttX is configured.
+
+ CONFIGURE_APPS += system/i2c
+
+I2C Tool Configuration Options
+------------------------------
+
+The default behavior of the I2C tool can be modified by the setting the
+options in the NuttX configuration. This configuration is the defconfig
+file in your configuration directory that is copied to the NuttX top-level
+directory as .config when NuttX is configured.
+
+ CONFIG_I2CTOOL_BUILTIN: Build the tools as an NSH built-in command
+ CONFIG_I2CTOOL_MINBUS: Smallest bus index supported by the hardware (default 0).
+ CONFIG_I2CTOOL_MAXBUS: Largest bus index supported by the hardware (default 3)
+ CONFIG_I2CTOOL_MINADDR: Minium device address (default: 0x03)
+ CONFIG_I2CTOOL_MAXADDR: Largest device address (default: 0x77)
+ CONFIG_I2CTOOL_MAXREGADDR: Largest register address (default: 0xff)
+ CONFIG_I2CTOOL_DEFFREQ: Default frequency (default: 4000000)
diff --git a/apps/system/i2c/i2c_bus.c b/apps/system/i2c/i2c_bus.c new file mode 100644 index 000000000..07e6d2da3 --- /dev/null +++ b/apps/system/i2c/i2c_bus.c @@ -0,0 +1,99 @@ +/**************************************************************************** + * apps/system/i2c/i2c_bus.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <nuttx/i2c.h> + +#include "i2ctool.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: i2ccmd_bus + ****************************************************************************/ + +int i2ccmd_bus(FAR struct i2ctool_s *i2ctool, int argc, char **argv) +{ + FAR struct i2c_dev_s *dev; + int i; + + i2ctool_printf(i2ctool, " BUS EXISTS?\n"); + for (i = CONFIG_I2CTOOL_MINBUS; i <= CONFIG_I2CTOOL_MAXBUS; i++) + { + dev = up_i2cinitialize(i); + if (dev) + { + i2ctool_printf(i2ctool, "Bus %d: YES\n", i); + (void)up_i2cuninitialize(dev); + } + else + { + i2ctool_printf(i2ctool, "Bus %d: NO\n", i); + } + } + + return OK; +} diff --git a/apps/system/i2c/i2c_common.c b/apps/system/i2c/i2c_common.c new file mode 100644 index 000000000..e7b27693a --- /dev/null +++ b/apps/system/i2c/i2c_common.c @@ -0,0 +1,216 @@ +/**************************************************************************** + * apps/system/i2c/i2c_common.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> + +#include "i2ctool.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: common_args + ****************************************************************************/ + +int common_args(FAR struct i2ctool_s *i2ctool, FAR char **arg) +{ + FAR char *ptr = *arg; + long value; + int ret; + + if (ptr[0] != '-') + { + goto invalid_argument; + } + + switch (ptr[1]) + { + case 'a': + ret = arg_hex(arg, &value); + if (value < CONFIG_I2CTOOL_MINADDR || value > CONFIG_I2CTOOL_MAXADDR) + { + goto out_of_range; + } + + i2ctool->addr = (uint8_t) value; + return ret; + + case 'b': + ret = arg_decimal(arg, &value); + if (value < CONFIG_I2CTOOL_MINBUS || value > CONFIG_I2CTOOL_MAXBUS) + { + goto out_of_range; + } + + i2ctool->bus = (uint8_t) value; + return ret; + + case 'f': + ret = arg_decimal(arg, &value); + if (value == 0) + { + goto out_of_range; + } + + i2ctool->freq = value; + return ret; + + case 'i': + i2ctool->autoincr = true; + return 1; + + case 'j': + i2ctool->autoincr = false; + return 1; + + case 'n': + i2ctool->start = false; + return 1; + + case 'r': + ret = arg_hex(arg, &value); + if (value < 0 || value > CONFIG_I2CTOOL_MAXREGADDR) + { + goto out_of_range; + } + + i2ctool->regaddr = (uint8_t) value; + return ret; + + case 's': + i2ctool->start = true; + return 1; + + case 'w': + ret = arg_decimal(arg, &value); + if (value != 8 && value != 16) + { + goto out_of_range; + } + + i2ctool->width = (uint8_t) value; + return ret; + + default: + goto invalid_argument; + } + +invalid_argument: + i2ctool_printf(i2ctool, g_i2carginvalid, ptr); + return ERROR; + +out_of_range: + i2ctool_printf(i2ctool, g_i2cargrange, ptr); + return ERROR; +} + +/**************************************************************************** + * Name: arg_string + ****************************************************************************/ + +int arg_string(FAR char **arg, FAR char **value) +{ + FAR char *ptr = *arg; + + if (ptr[2] == '\0') + { + *value = arg[1]; + return 2; + } + else + { + *value = &ptr[2]; + return 1; + } +} + +/**************************************************************************** + * Name: arg_decimal + ****************************************************************************/ + +int arg_decimal(FAR char **arg, FAR long *value) +{ + FAR char *string; + int ret; + + ret = arg_string(arg, &string); + *value = strtol(string, NULL, 10); + return ret; +} + +/**************************************************************************** + * Name: arg_hex + ****************************************************************************/ + +int arg_hex(FAR char **arg, FAR long *value) +{ + FAR char *string; + int ret; + + ret = arg_string(arg, &string); + *value = strtol(string, NULL, 16); + return ret; +} diff --git a/apps/system/i2c/i2c_dev.c b/apps/system/i2c/i2c_dev.c new file mode 100644 index 000000000..f2b5a0e21 --- /dev/null +++ b/apps/system/i2c/i2c_dev.c @@ -0,0 +1,235 @@ +/**************************************************************************** + * apps/system/i2c/i2c_dev.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> + +#include <nuttx/i2c.h> + +#include "i2ctool.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: i2ccmd_dev + ****************************************************************************/ + +int i2ccmd_dev(FAR struct i2ctool_s *i2ctool, int argc, char **argv) +{ + FAR struct i2c_dev_s *dev; + struct i2c_msg_s msg[2]; + FAR char *ptr; + union + { + uint16_t data16; + uint8_t data8; + } u; + + uint8_t regaddr; + long first; + long last; + int addr; + int nargs; + int argndx; + int ret; + int i; + int j; + + /* Parse any command line arguments */ + + for (argndx = 1; argndx < argc; ) + { + /* Break out of the look when the last option has been parsed */ + + ptr = argv[argndx]; + if (*ptr != '-') + { + break; + } + + /* Otherwise, check for common options */ + + nargs = common_args(i2ctool, &argv[argndx]); + if (nargs < 0) + { + return ERROR; + } + argndx += nargs; + } + + /* There should be exactly two more things on the command line: The first and + * last addresses to be probed. + */ + + if (argndx+1 < argc) + { + first = strtol(argv[argndx], NULL, 16); + last = strtol(argv[argndx+1], NULL, 16); + if (first < 0 || first > 0x7f || last < 0 || last > 0x7f || first > last) + { + i2ctool_printf(i2ctool, g_i2cargrange, argv[0]); + return ERROR; + } + + argndx += 2; + } + else + { + i2ctool_printf(i2ctool, g_i2cargrequired, argv[0]); + return ERROR; + } + + if (argndx != argc) + { + i2ctool_printf(i2ctool, g_i2ctoomanyargs, argv[0]); + return ERROR; + } + + /* Get a handle to the I2C bus */ + + dev = up_i2cinitialize(i2ctool->bus); + if (!dev) + { + i2ctool_printf(i2ctool, "Failed to get bus %d\n", i2ctool->bus); + return ERROR; + } + + /* Set the frequency and address (NOTE: Only 7-bit address supported now) */ + + I2C_SETFREQUENCY(dev, i2ctool->freq); + + /* Probe each address */ + + i2ctool_printf(i2ctool, " 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); + for (i = 0; i < 128; i += 16) + { + i2ctool_printf(i2ctool, "%02x: ", i); + for (j = 0; j < 16; j++) + { + /* Skip addresses that are out of the selected range */ + + addr = i+j; + if (addr < first || addr > last) + { + i2ctool_printf(i2ctool, " "); + continue; + } + + /* Set the I2C address */ + + I2C_SETADDRESS(dev, addr, 7); + + /* Set up data structures */ + + regaddr = 0; + + msg[0].addr = addr; + msg[0].flags = 0; + msg[0].buffer = ®addr; + msg[0].length = 1; + + msg[1].addr = addr; + msg[1].flags = I2C_M_READ; + if (i2ctool->width == 8) + { + msg[1].buffer = &u.data8; + msg[1].length = 1; + } + else + { + msg[1].buffer = (uint8_t*)&u.data16; + msg[1].length = 2; + } + + if (i2ctool->start) + { + ret = I2C_TRANSFER(dev, &msg[0], 1); + if (ret == OK) + { + ret = I2C_TRANSFER(dev, &msg[1], 1); + } + } + else + { + ret = I2C_TRANSFER(dev, msg, 2); + } + + if (ret == OK) + { + i2ctool_printf(i2ctool, "%02x ", addr); + } + else + { + i2ctool_printf(i2ctool, "-- "); + } + } + i2ctool_printf(i2ctool, "\n"); + i2ctool_flush(i2ctool); + } + + (void)up_i2cuninitialize(dev); + return OK; +} diff --git a/apps/system/i2c/i2c_get.c b/apps/system/i2c/i2c_get.c new file mode 100644 index 000000000..773f2c963 --- /dev/null +++ b/apps/system/i2c/i2c_get.c @@ -0,0 +1,257 @@ +/**************************************************************************** + * apps/system/i2c/i2c_get.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> + +#include <nuttx/i2c.h> + +#include "i2ctool.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: i2ccmd_get + ****************************************************************************/ + +int i2ccmd_get(FAR struct i2ctool_s *i2ctool, int argc, FAR char **argv) +{ + FAR struct i2c_dev_s *dev; + FAR char *ptr; + uint16_t result; + uint8_t regaddr; + long repititions; + int nargs; + int argndx; + int ret; + int i; + + /* Parse any command line arguments */ + + for (argndx = 1; argndx < argc; ) + { + /* Break out of the look when the last option has been parsed */ + + ptr = argv[argndx]; + if (*ptr != '-') + { + break; + } + + /* Otherwise, check for common options */ + + nargs = common_args(i2ctool, &argv[argndx]); + if (nargs < 0) + { + return ERROR; + } + argndx += nargs; + } + + /* There may be one more thing on the command line: The repitition + * count. + */ + + repititions = 1; + if (argndx < argc) + { + repititions = strtol(argv[argndx], NULL, 16); + if (repititions < 1) + { + i2ctool_printf(i2ctool, g_i2cargrange, argv[0]); + return ERROR; + } + + argndx++; + } + + if (argndx != argc) + { + i2ctool_printf(i2ctool, g_i2ctoomanyargs, argv[0]); + return ERROR; + } + + /* Get a handle to the I2C bus */ + + dev = up_i2cinitialize(i2ctool->bus); + if (!dev) + { + i2ctool_printf(i2ctool, "Failed to get bus %d\n", i2ctool->bus); + return ERROR; + } + + /* Set the frequency and the address (NOTE: Only 7-bit address supported now) */ + + I2C_SETFREQUENCY(dev, i2ctool->freq); + I2C_SETADDRESS(dev, i2ctool->addr, 7); + + /* Loop for the requested number of repititions */ + + regaddr = i2ctool->regaddr; + ret = OK; + + for (i = 0; i < repititions; i++) + { + /* Read from the I2C bus */ + + ret = i2ctool_get(i2ctool, dev, regaddr, &result); + + /* Display the result */ + + if (ret == OK) + { + i2ctool_printf(i2ctool, "READ Bus: %d Addr: %02x Subaddr: %02x Value: ", + i2ctool->bus, i2ctool->addr, i2ctool->regaddr); + if (i2ctool->width == 8) + { + i2ctool_printf(i2ctool, "%02x\n", result); + } + else + { + i2ctool_printf(i2ctool, "%04x\n", result); + } + } + else + { + i2ctool_printf(i2ctool, g_i2cxfrerror, argv[0], -ret); + break; + } + + /* Auto-increment the address if so configured */ + + if (i2ctool->autoincr) + { + regaddr++; + } + } + + (void)up_i2cuninitialize(dev); + return ret; +} + +/**************************************************************************** + * Name: i2ctool_get + ****************************************************************************/ + +int i2ctool_get(FAR struct i2ctool_s *i2ctool, FAR struct i2c_dev_s *dev, + uint8_t regaddr, uint16_t *result) +{ + struct i2c_msg_s msg[2]; + union + { + uint16_t data16; + uint8_t data8; + } u; + int ret; + + /* Set up data structures */ + + msg[0].addr = i2ctool->addr; + msg[0].flags = 0; + msg[0].buffer = ®addr; + msg[0].length = 1; + + msg[1].addr = i2ctool->addr; + msg[1].flags = I2C_M_READ; + if (i2ctool->width == 8) + { + msg[1].buffer = &u.data8; + msg[1].length = 1; + } + else + { + msg[1].buffer = (uint8_t*)&u.data16; + msg[1].length = 2; + } + + if (i2ctool->start) + { + ret = I2C_TRANSFER(dev, &msg[0], 1); + if (ret== OK) + { + ret = I2C_TRANSFER(dev, &msg[1], 1); + } + } + else + { + ret = I2C_TRANSFER(dev, msg, 2); + } + + /* Return the result of the read operation */ + + if (ret == OK) + { + if (i2ctool->width == 8) + { + *result = (uint16_t)u.data8; + } + else + { + *result = u.data16; + } + } + return ret; +} diff --git a/apps/system/i2c/i2c_main.c b/apps/system/i2c/i2c_main.c new file mode 100644 index 000000000..2a0e5d626 --- /dev/null +++ b/apps/system/i2c/i2c_main.c @@ -0,0 +1,454 @@ +/**************************************************************************** + * apps/system/i2c/i2c_main.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdarg.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include "i2ctool.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int i2ccmd_help(FAR struct i2ctool_s *i2ctool, int argc, char **argv); +static int i2ccmd_unrecognized(FAR struct i2ctool_s *i2ctool, int argc, char **argv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct i2ctool_s g_i2ctool; + +static const struct cmdmap_s g_i2ccmds[] = +{ + { "?", i2ccmd_help, "Show help ", NULL }, + { "bus", i2ccmd_bus, "List busses ", NULL }, + { "dev", i2ccmd_dev, "List devices ", "[OPTIONS] <first> <last>" }, + { "get", i2ccmd_get, "Read register ", "[OPTIONS] [<repititions>]" }, + { "help", i2ccmd_help, "Show help ", NULL }, + { "set", i2ccmd_set, "Write register", "[OPTIONS] <value> [<repititions>]" }, + { "verf", i2ccmd_verf, "Verify access ", "[OPTIONS] [<value>] [<repititions>]" }, + { NULL, NULL, NULL, NULL } +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Common, message formats */ + +const char g_i2cargrequired[] = "i2ctool: %s: missing required argument(s)\n"; +const char g_i2carginvalid[] = "i2ctool: %s: argument invalid\n"; +const char g_i2cargrange[] = "i2ctool: %s: value out of range\n"; +const char g_i2ccmdnotfound[] = "i2ctool: %s: command not found\n"; +const char g_i2ctoomanyargs[] = "i2ctool: %s: too many arguments\n"; +const char g_i2ccmdfailed[] = "i2ctool: %s: %s failed: %d\n"; +const char g_i2cxfrerror[] = "i2ctool: %s: Transfer failed: %d\n"; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: i2ccmd_help + ****************************************************************************/ + +static int i2ccmd_help(FAR struct i2ctool_s *i2ctool, int argc, char **argv) +{ + const struct cmdmap_s *ptr; + + i2ctool_printf(i2ctool, "Usage: i2c <cmd> [arguments]\n"); + i2ctool_printf(i2ctool, "Where <cmd> is one of:\n\n"); + for (ptr = g_i2ccmds; ptr->cmd; ptr++) + { + if (ptr->usage) + { + i2ctool_printf(i2ctool, " %s: %s %s\n", ptr->desc, ptr->cmd, ptr->usage); + } + else + { + i2ctool_printf(i2ctool, " %s: %s\n", ptr->desc, ptr->cmd); + } + } + + i2ctool_printf(i2ctool, "\nWhere common \"sticky\" OPTIONS include:\n"); + i2ctool_printf(i2ctool, " [-a addr] is the I2C device address (hex). " + "Default: %02x Current: %02x\n", + CONFIG_I2CTOOL_MINADDR, i2ctool->addr); + i2ctool_printf(i2ctool, " [-b bus] is the I2C bus number (decimal). " + "Default: %d Current: %d\n", + CONFIG_I2CTOOL_MINBUS, i2ctool->bus); + i2ctool_printf(i2ctool, " [-r regaddr] is the I2C device register address (hex). " + "Default: 00 Current: %02x\n", + i2ctool->regaddr); + i2ctool_printf(i2ctool, " [-w width] is the data width (8 or 16 decimal). " + "Default: 8 Current: %d\n", + i2ctool->width); + i2ctool_printf(i2ctool, " [-s|n], send/don't send start between command and data. " + "Default: -n Current: %s\n", + i2ctool->start ? "-s" : "-n"); + i2ctool_printf(i2ctool, " [-i|j], Auto increment|don't increment regaddr on repititions. " + "Default: NO Current: %s\n", + i2ctool->autoincr ? "YES" : "NO"); + i2ctool_printf(i2ctool, " [-f freq] I2C frequency. " + "Default: %d Current: %d\n", + CONFIG_I2CTOOL_DEFFREQ, i2ctool->freq); + i2ctool_printf(i2ctool, "\nNOTES:\n"); +#ifndef CONFIG_DISABLE_ENVIRON + i2ctool_printf(i2ctool, "o An environment variable like $PATH may be used for any argument.\n"); +#endif + i2ctool_printf(i2ctool, "o Arguments are \"sticky\". For example, once the I2C address is\n"); + i2ctool_printf(i2ctool, " specified, that address will be re-used until it is changed.\n"); + i2ctool_printf(i2ctool, "\nWARNING:\n"); + i2ctool_printf(i2ctool, "o The I2C dev command may have bad side effects on your I2C devices.\n"); + i2ctool_printf(i2ctool, " Use only at your own risk.\n"); + return OK; +} + +/**************************************************************************** + * Name: i2ccmd_unrecognized + ****************************************************************************/ + +static int i2ccmd_unrecognized(FAR struct i2ctool_s *i2ctool, int argc, char **argv) +{ + i2ctool_printf(i2ctool, g_i2ccmdnotfound, argv[0]); + return ERROR; +} + +/**************************************************************************** + * Name: i2c_execute + ****************************************************************************/ + +static int i2c_execute(FAR struct i2ctool_s *i2ctool, int argc, char *argv[]) +{ + const struct cmdmap_s *cmdmap; + const char *cmd; + cmd_t handler; + int ret; + + /* The form of argv is: + * + * argv[0]: The command name. This is argv[0] when the arguments + * are, finally, received by the command vtblr + * argv[1]: The beginning of argument (up to MAX_ARGUMENTS) + * argv[argc]: NULL terminating pointer + */ + + /* See if the command is one that we understand */ + + cmd = argv[0]; + handler = i2ccmd_unrecognized; + + for (cmdmap = g_i2ccmds; cmdmap->cmd; cmdmap++) + { + if (strcmp(cmdmap->cmd, cmd) == 0) + { + handler = cmdmap->handler; + break; + } + } + + ret = handler(i2ctool, argc, argv); + return ret; +} + +/**************************************************************************** + * Name: i2c_argument + ****************************************************************************/ + +FAR char *i2c_argument(FAR struct i2ctool_s *i2ctool, int argc, char *argv[], int *pindex) +{ + FAR char *arg; + int index = *pindex; + + /* If we are at the end of the arguments with nothing, then return NULL */ + + if (index >= argc) + { + return NULL; + } + + /* Get the return parameter */ + + arg = argv[index]; + *pindex = index + 1; + +#ifndef CONFIG_DISABLE_ENVIRON + /* Check for references to environment variables */ + + if (arg[0] == '$') + { + /* Return the value of the environment variable with this name */ + + FAR char *value = getenv(arg+1); + if (value) + { + return value; + } + else + { + return (FAR char*)""; + } + } +#endif + + /* Return the next argument. */ + + return arg; +} + +/**************************************************************************** + * Name: i2c_parse + ****************************************************************************/ + +int i2c_parse(FAR struct i2ctool_s *i2ctool, int argc, char *argv[]) +{ + FAR char *newargs[MAX_ARGUMENTS+2]; + FAR char *cmd; + int nargs; + int index; + + /* Parse out the command, skipping the first argument (the program name)*/ + + index = 1; + cmd = i2c_argument(i2ctool, argc, argv, &index); + + /* Check if any command was provided */ + + if (!cmd) + { + /* An empty line is not an error and an unprocessed command cannot + * generate an error, but neither should they change the last + * command status. + */ + + return i2ccmd_help(i2ctool, 0, NULL); + } + + /* Parse all of the arguments following the command name. */ + + newargs[0] = cmd; + for (nargs = 1; nargs <= MAX_ARGUMENTS; nargs++) + { + newargs[nargs] = i2c_argument(i2ctool, argc, argv, &index); + if (!newargs[nargs]) + { + break; + } + } + newargs[nargs] = NULL; + + /* Then execute the command */ + + return i2c_execute(i2ctool, nargs, newargs); +} + +/**************************************************************************** + * Name: i2c_setup + ****************************************************************************/ + +static inline int i2c_setup(FAR struct i2ctool_s *i2ctool) +{ + /* Initialize the output stream */ + +#ifdef CONFIG_I2CTOOL_OUTDEV + i2ctool->ss_outfd = open(CONFIG_I2CTOOL_OUTDEV, O_WRONLY); + if (i2ctool->ss_outfd < 0) + { + fprintf(stderr, g_i2ccmdfailed, "open", errno); + return ERROR; + } + + /* Create a standard C stream on the console device */ + + i2ctool->ss_outstream = fdopen(i2ctool->ss_outfd, "w"); + if (!i2ctool->ss_outstream) + { + fprintf(stderr, g_i2ccmdfailed, "fdopen", errno); + return ERROR; + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: i2c_teardown + * + * Description: + * Close the output stream if it is not the standard output stream. + * + ****************************************************************************/ + +static void i2c_teardown(FAR struct i2ctool_s *i2ctool) +{ + fflush(OUTSTREAM(&g_i2ctool)); + +#ifdef CONFIG_I2CTOOL_OUTDEV + fclose(i2ctool->ss_outstream); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: i2c_main + ****************************************************************************/ + +#ifdef CONFIG_I2CTOOL_BUILTIN +# define MAIN_NAME i2c_main +# define MAIN_NAME_STRING "i2c_main" +#else +# define MAIN_NAME user_start +# define MAIN_NAME_STRING "user_start" +#endif + +int MAIN_NAME(int argc, char *argv[]) +{ + /* Verify settings */ + + if (g_i2ctool.bus < CONFIG_I2CTOOL_MINBUS || g_i2ctool.bus > CONFIG_I2CTOOL_MAXBUS) + { + g_i2ctool.bus = CONFIG_I2CTOOL_MINBUS; + } + + if (g_i2ctool.addr < CONFIG_I2CTOOL_MINADDR || g_i2ctool.addr > CONFIG_I2CTOOL_MAXADDR) + { + g_i2ctool.addr = CONFIG_I2CTOOL_MINADDR; + } + + if (g_i2ctool.regaddr < CONFIG_I2CTOOL_MAXREGADDR) + { + g_i2ctool.regaddr = 0; + } + + if (g_i2ctool.width != 8 && g_i2ctool.width != 16) + { + g_i2ctool.width = 8; + } + + if (g_i2ctool.freq == 0) + { + g_i2ctool.freq = CONFIG_I2CTOOL_DEFFREQ; + } + + /* Parse process the command line */ + + i2c_setup(&g_i2ctool); + (void)i2c_parse(&g_i2ctool, argc, argv); + + i2ctool_flush(&g_i2ctool); + i2c_teardown(&g_i2ctool); + return OK; +} + +/**************************************************************************** + * Name: i2ctool_printf + * + * Description: + * Print a string to the currently selected stream. + * + ****************************************************************************/ + +int i2ctool_printf(FAR struct i2ctool_s *i2ctool, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vfprintf(OUTSTREAM(i2ctool), fmt, ap); + va_end(ap); + + return ret; +} + +/**************************************************************************** + * Name: i2ctool_write + * + * Description: + * write a buffer to the currently selected stream. + * + ****************************************************************************/ + +ssize_t i2ctool_write(FAR struct i2ctool_s *i2ctool, FAR const void *buffer, size_t nbytes) +{ + ssize_t ret; + + /* Write the data to the output stream */ + + ret = fwrite(buffer, 1, nbytes, OUTSTREAM(i2ctool)); + if (ret < 0) + { + dbg("[%d] Failed to send buffer: %d\n", OUTFD(i2ctool), errno); + } + return ret; +} + +/**************************************************************************** + * Name: i2ctool_flush + * + * Description: + * Flush buffered I/O to the currently selected stream. + * + ****************************************************************************/ + +void i2ctool_flush(FAR struct i2ctool_s *i2ctool) +{ + fflush(OUTSTREAM(i2ctool)); +} diff --git a/apps/system/i2c/i2c_set.c b/apps/system/i2c/i2c_set.c new file mode 100644 index 000000000..66fd8c85a --- /dev/null +++ b/apps/system/i2c/i2c_set.c @@ -0,0 +1,275 @@ +/**************************************************************************** + * apps/system/i2c/i2c_set.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> + +#include <nuttx/i2c.h> + +#include "i2ctool.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: i2ccmd_set + ****************************************************************************/ + +int i2ccmd_set(FAR struct i2ctool_s *i2ctool, int argc, FAR char **argv) +{ + FAR struct i2c_dev_s *dev; + FAR char *ptr; + uint8_t regaddr; + long value; + long repititions; + int nargs; + int argndx; + int ret; + int i; + + /* Parse any command line arguments */ + + for (argndx = 1; argndx < argc; ) + { + /* Break out of the look when the last option has been parsed */ + + ptr = argv[argndx]; + if (*ptr != '-') + { + break; + } + + /* Otherwise, check for common options */ + + nargs = common_args(i2ctool, &argv[argndx]); + if (nargs < 0) + { + return ERROR; + } + argndx += nargs; + } + + /* There must be at least one more thing on the command line: The value + * to be written. + */ + + if (argndx < argc) + { + value = strtol(argv[argndx], NULL, 16); + if (i2ctool->width == 8) + { + if (value < 0 || value > 255) + { + i2ctool_printf(i2ctool, g_i2cargrange, argv[0]); + return ERROR; + } + } + else if (value < 0 || value > 65535) + { + i2ctool_printf(i2ctool, g_i2cargrange, argv[0]); + return ERROR; + } + + argndx++; + } + else + { + i2ctool_printf(i2ctool, g_i2cargrequired, argv[0]); + return ERROR; + } + + /* There may be one more thing on the command line: The repitition + * count. + */ + + repititions = 1; + if (argndx < argc) + { + repititions = strtol(argv[argndx], NULL, 16); + if (repititions < 1) + { + i2ctool_printf(i2ctool, g_i2cargrange, argv[0]); + return ERROR; + } + + argndx++; + } + + if (argndx != argc) + { + i2ctool_printf(i2ctool, g_i2ctoomanyargs, argv[0]); + return ERROR; + } + + /* Get a handle to the I2C bus */ + + dev = up_i2cinitialize(i2ctool->bus); + if (!dev) + { + i2ctool_printf(i2ctool, "Failed to get bus %d\n", i2ctool->bus); + return ERROR; + } + + /* Set the frequency and the address (NOTE: Only 7-bit address supported now) */ + + I2C_SETFREQUENCY(dev, i2ctool->freq); + I2C_SETADDRESS(dev, i2ctool->addr, 7); + + /* Loop for the requested number of repititions */ + + regaddr = i2ctool->regaddr; + ret = OK; + + for (i = 0; i < repititions; i++) + { + /* Write to the I2C bus */ + + ret = i2ctool_set(i2ctool, dev, regaddr, (uint16_t)value); + + /* Display the result */ + + if (ret == OK) + { + i2ctool_printf(i2ctool, "WROTE Bus: %d Addr: %02x Subaddr: %02x Value: ", + i2ctool->bus, i2ctool->addr, i2ctool->regaddr); + if (i2ctool->width == 8) + { + i2ctool_printf(i2ctool, "%02x\n", (int)value); + } + else + { + i2ctool_printf(i2ctool, "%04x\n", (int)value); + } + } + else + { + i2ctool_printf(i2ctool, g_i2cxfrerror, argv[0], -ret); + break; + } + + /* Auto-increment the address if so configured */ + + if (i2ctool->autoincr) + { + regaddr++; + } + } + + (void)up_i2cuninitialize(dev); + return ret; +} + +/**************************************************************************** + * Name: i2ctool_set + ****************************************************************************/ + +int i2ctool_set(FAR struct i2ctool_s *i2ctool, FAR struct i2c_dev_s *dev, + uint8_t regaddr, uint16_t value) +{ + struct i2c_msg_s msg[2]; + union + { + uint16_t data16; + uint8_t data8; + } u; + int ret; + + /* Set up data structures */ + + msg[0].addr = i2ctool->addr; + msg[0].flags = 0; + msg[0].buffer = ®addr; + msg[0].length = 1; + + msg[1].addr = i2ctool->addr; + msg[1].flags = 0; + if (i2ctool->width == 8) + { + u.data8 = (uint8_t)value; + msg[1].buffer = &u.data8; + msg[1].length = 1; + } + else + { + u.data16 = value; + msg[1].buffer = (uint8_t*)&u.data16; + msg[1].length = 2; + } + + if (i2ctool->start) + { + ret = I2C_TRANSFER(dev, &msg[0], 1); + if (ret == OK) + { + ret = I2C_TRANSFER(dev, &msg[1], 1); + } + } + else + { + ret = I2C_TRANSFER(dev, msg, 2); + } + + return ret; +} diff --git a/apps/system/i2c/i2c_verf.c b/apps/system/i2c/i2c_verf.c new file mode 100644 index 000000000..0fa34b96e --- /dev/null +++ b/apps/system/i2c/i2c_verf.c @@ -0,0 +1,249 @@ +/**************************************************************************** + * apps/system/i2c/i2c_verf.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> + +#include <nuttx/i2c.h> + +#include "i2ctool.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: i2ccmd_verf + ****************************************************************************/ + +int i2ccmd_verf(FAR struct i2ctool_s *i2ctool, int argc, FAR char **argv) +{ + FAR struct i2c_dev_s *dev; + FAR char *ptr; + uint16_t rdvalue; + uint8_t regaddr; + bool addrinaddr; + long wrvalue; + long repititions; + int nargs; + int argndx; + int ret; + int i; + + /* Parse any command line arguments */ + + for (argndx = 1; argndx < argc; ) + { + /* Break out of the look when the last option has been parsed */ + + ptr = argv[argndx]; + if (*ptr != '-') + { + break; + } + + /* Otherwise, check for common options */ + + nargs = common_args(i2ctool, &argv[argndx]); + if (nargs < 0) + { + return ERROR; + } + argndx += nargs; + } + + /* The options may be followed by the optional wrvalue to be written. If omitted, then + * the register address will be used as the wrvalue, providing an address-in-address + * test. + */ + + addrinaddr = true; + wrvalue = 0; + + if (argndx < argc) + { + wrvalue = strtol(argv[argndx], NULL, 16); + if (i2ctool->width == 8) + { + if (wrvalue < 0 || wrvalue > 255) + { + i2ctool_printf(i2ctool, g_i2cargrange, argv[0]); + return ERROR; + } + } + else if (wrvalue < 0 || wrvalue > 65535) + { + i2ctool_printf(i2ctool, g_i2cargrange, argv[0]); + return ERROR; + } + + addrinaddr = false; + argndx++; + } + + /* There may be one more thing on the command line: The repitition + * count. + */ + + repititions = 1; + if (argndx < argc) + { + repititions = strtol(argv[argndx], NULL, 16); + if (repititions < 1) + { + i2ctool_printf(i2ctool, g_i2cargrange, argv[0]); + return ERROR; + } + + argndx++; + } + + if (argndx != argc) + { + i2ctool_printf(i2ctool, g_i2ctoomanyargs, argv[0]); + return ERROR; + } + + /* Get a handle to the I2C bus */ + + dev = up_i2cinitialize(i2ctool->bus); + if (!dev) + { + i2ctool_printf(i2ctool, "Failed to get bus %d\n", i2ctool->bus); + return ERROR; + } + + /* Set the frequency and the address (NOTE: Only 7-bit address supported now) */ + + I2C_SETFREQUENCY(dev, i2ctool->freq); + I2C_SETADDRESS(dev, i2ctool->addr, 7); + + /* Loop for the requested number of repititions */ + + regaddr = i2ctool->regaddr; + ret = OK; + + for (i = 0; i < repititions; i++) + { + /* If we are performing an address-in-address test, then use the register + * address as the value to write. + */ + + if (addrinaddr) + { + wrvalue = regaddr; + } + + /* Write to the I2C bus */ + + ret = i2ctool_set(i2ctool, dev, regaddr, (uint16_t)wrvalue); + if (ret == OK) + { + /* Read the value back from the I2C bus */ + + ret = i2ctool_get(i2ctool, dev, regaddr, &rdvalue); + } + + /* Display the result */ + + if (ret == OK) + { + i2ctool_printf(i2ctool, "VERIFY Bus: %d Addr: %02x Subaddr: %02x Wrote: ", + i2ctool->bus, i2ctool->addr, i2ctool->regaddr); + + if (i2ctool->width == 8) + { + i2ctool_printf(i2ctool, "%02x Read: %02x", (int)wrvalue, (int)rdvalue); + } + else + { + i2ctool_printf(i2ctool, "%04x Read: %04x", (int)wrvalue, (int)rdvalue); + } + + if (wrvalue != rdvalue) + { + i2ctool_printf(i2ctool, " <<< FAILURE\n"); + } + else + { + i2ctool_printf(i2ctool, "\n"); + } + } + else + { + i2ctool_printf(i2ctool, g_i2cxfrerror, argv[0], -ret); + break; + } + + /* Auto-increment the address if so configured */ + + if (i2ctool->autoincr) + { + regaddr++; + } + } + + (void)up_i2cuninitialize(dev); + return ret; +} diff --git a/apps/system/i2c/i2ctool.h b/apps/system/i2c/i2ctool.h new file mode 100644 index 000000000..9726f0083 --- /dev/null +++ b/apps/system/i2c/i2ctool.h @@ -0,0 +1,210 @@ +/**************************************************************************** + * apps/system/i2c/i2ctool.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __APPS_SYSTEM_I2C_I2CTOOLS_H +#define __APPS_SYSTEM_I2C_I2CTOOLS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/compiler.h> + +#include <sys/types.h> +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> + +#include <nuttx/i2c.h> + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* CONFIG_I2CTOOL_BUILTIN - Build the tools as an NSH built-in command + * CONFIG_I2CTOOL_MINBUS - Smallest bus index supported by the hardware (default 0). + * CONFIG_I2CTOOL_MAXBUS - Largest bus index supported by the hardware (default 3) + * CONFIG_I2CTOOL_MINADDR - Minium device address (default: 0x03) + * CONFIG_I2CTOOL_MAXADDR - Largest device address (default: 0x77) + * CONFIG_I2CTOOL_MAXREGADDR - Largest register address (default: 0xff) + * CONFIG_I2CTOOL_DEFFREQ - Default frequency (default: 4000000) + */ + +#ifndef CONFIG_I2C_TRANSFER +# error "CONFIG_I2C_TRANSFER is required in the configuration" +#endif + +#ifndef CONFIG_I2CTOOL_MINBUS +# define CONFIG_I2CTOOL_MINBUS 0 +#endif + +#ifndef CONFIG_I2CTOOL_MAXBUS +# define CONFIG_I2CTOOL_MAXBUS 3 +#endif + +#ifndef CONFIG_I2CTOOL_MINADDR +# define CONFIG_I2CTOOL_MINADDR 0x03 +#endif + +#ifndef CONFIG_I2CTOOL_MAXADDR +# define CONFIG_I2CTOOL_MAXADDR 0x77 +#endif + +#ifndef CONFIG_I2CTOOL_MAXREGADDR +# define CONFIG_I2CTOOL_MAXREGADDR 0xff +#endif + +#ifndef CONFIG_I2CTOOL_DEFFREQ +# define CONFIG_I2CTOOL_DEFFREQ 100000 +#endif + +/* This is the maximum number of arguments that will be accepted for a + * command. The only real limit is in the OS configuration that limits + * the number of parameters passed to a task. + */ + +#define MAX_ARGUMENTS (CONFIG_MAX_TASK_ARGS-1) + +/* Maximum size of one command line */ + +#define MAX_LINELEN 80 + +/* Are we using the NuttX console for I/O? Or some other character device? */ + +#ifdef CONFIG_I2CTOOL_INDEV +# define INFD(p) ((p)->ss_infd) +# define INSTREAM(p) ((p)->ss_instream) +#else +# define INFD(p) 0 +# define INSTREAM(p) stdin +#endif + +#ifdef CONFIG_I2CTOOL_OUTDEV +# define OUTFD(p) ((p)->ss_outfd) +# define OUTSTREAM(p) ((p)->ss_outstream) +#else +# define OUTFD(p) 1 +# define OUTSTREAM(p) stdout +#endif + +/* Output is via printf but can be changed using this macro */ + +#ifdef CONFIG_CPP_HAVE_VARARGS +# define i2c_output(v, fmt...) printf(v, ##fmt) +#else +# define i2c_output printf +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct i2ctool_s +{ + /* Sticky options */ + + uint8_t addr; /* [-a addr] is the I2C device address */ + uint8_t bus; /* [-b bus] is the I2C bus number */ + uint8_t regaddr; /* [-r regaddr] is the I2C device register address */ + uint8_t width; /* [-w width] is the data width (8 or 16) */ + bool start; /* [-s|n], send|don't send start between command and data */ + bool autoincr; /* [-i|j], Auto increment|don't increment regaddr on repititions */ + uint32_t freq; /* [-f freq] I2C frequency */ + + /* Output streams */ + +#ifdef CONFIG_I2CTOOL_OUTDEV + int ss_outfd; /* Output file descriptor */ + FILE *ss_outstream; /* Output stream */ +#endif +}; + +typedef int (*cmd_t)(FAR struct i2ctool_s *i2ctool, int argc, FAR char **argv); + +struct cmdmap_s +{ + FAR const char *cmd; /* Name of the command */ + cmd_t handler; /* Function that handles the command */ + FAR const char *desc; /* Short description */ + FAR const char *usage; /* Usage instructions for 'help' command */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern const char g_i2cargrequired[]; +extern const char g_i2carginvalid[]; +extern const char g_i2cargrange[]; +extern const char g_i2ccmdnotfound[]; +extern const char g_i2ctoomanyargs[]; +extern const char g_i2ccmdfailed[]; +extern const char g_i2cxfrerror[]; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Message handler */ + +ssize_t i2ctool_write(FAR struct i2ctool_s *i2ctool, FAR const void *buffer, size_t nbytes); +int i2ctool_printf(FAR struct i2ctool_s *i2ctool, const char *fmt, ...); +void i2ctool_flush(FAR struct i2ctool_s *i2ctool); + +/* Command handlers */ + +int i2ccmd_bus(FAR struct i2ctool_s *i2ctool, int argc, FAR char **argv); +int i2ccmd_dev(FAR struct i2ctool_s *i2ctool, int argc, FAR char **argv); +int i2ccmd_get(FAR struct i2ctool_s *i2ctool, int argc, FAR char **argv); +int i2ccmd_set(FAR struct i2ctool_s *i2ctool, int argc, FAR char **argv); +int i2ccmd_verf(FAR struct i2ctool_s *i2ctool, int argc, FAR char **argv); + +/* I2C access functions */ + +int i2ctool_get(FAR struct i2ctool_s *i2ctool, FAR struct i2c_dev_s *dev, + uint8_t addr, uint16_t *result); +int i2ctool_set(FAR struct i2ctool_s *i2ctool, FAR struct i2c_dev_s *dev, + uint8_t regaddr, uint16_t value); + +/* Common logic */ + +int common_args(FAR struct i2ctool_s *i2ctool, FAR char **arg); +int arg_string(FAR char **arg, FAR char **value); +int arg_decimal(FAR char **arg, FAR long *value); +int arg_hex(FAR char **arg, FAR long *value); + +#endif /* __APPS_SYSTEM_I2C_I2CTOOLS_H */ diff --git a/apps/system/install/Makefile b/apps/system/install/Makefile new file mode 100755 index 000000000..4528ad44e --- /dev/null +++ b/apps/system/install/Makefile @@ -0,0 +1,114 @@ +############################################################################ +# apps/system/install/Makefile +# +# Copyright (C) 2011 Uros Platise. All rights reserved. +# Author: Uros Platise <uros.platise@isotel.eu> +# Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TODO, this makefile should run make under the app dirs, instead of +# sourcing the Make.defs! + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +# Hello Application +# TODO: appname can be automatically extracted from the directory name + +APPNAME = install +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 1024 + +ASRCS = +CSRCS = install.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +# Register application + +.context: + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ + +context: .context + +# Create dependencies + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f .context Make.dep .depend + +-include Make.dep diff --git a/apps/system/install/README.txt b/apps/system/install/README.txt new file mode 100755 index 000000000..66e9b0939 --- /dev/null +++ b/apps/system/install/README.txt @@ -0,0 +1,26 @@ + +Install Program +=============== + + Source: NuttX + Author: Uros Platise + Date: 7. May 2011 + +This application installs XIP application by placing it directly into +the program memory (flash) area into free area and creates a start-up +script into selected directory (i.e. /usr/bin/progname). + +Usage: + install [--stack RequiredStackSpace] [--priority Priority] + source-file destination-directory + +If stackspace is not given default stack space of 4096 Bytes is used. +If priority is not given system default is used. + +Additional options: + + --remove destination-file i.e. install --remove /usr/bin/myapp + --force to replace existing installation + --start <page> install app at or after <page> + --margin <pages> leave some free space after the kernel + Default is 16 pages so kernel may grow. diff --git a/apps/system/install/install.c b/apps/system/install/install.c new file mode 100755 index 000000000..2f11c6434 --- /dev/null +++ b/apps/system/install/install.c @@ -0,0 +1,412 @@ +/**************************************************************************** + * apps/system/install/install.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise <uros.platise@isotel.eu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/progmem.h> +#include <sys/stat.h> + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define ACTION_INSTALL 0x01 +#define ACTION_REMOVE 0x00 +#define ACTION_REINSTALL 0x03 +#define ACTION_INSUFPARAM 0x80 + +#define INSTALL_PROGRAMBLOCKSIZE 1024 + + +/**************************************************************************** + * Private data + ****************************************************************************/ + +const char *install_help = + "Installs XIP program into flash and creates a start-up script in the\n" + "destination directory.\n\n" + "Usage:\t%s [options] source-file.xip destination-directory\n\n" + "Example:\n\t%s --stack 1024 /sdcard/demo.xip /usr/bin\n\n" + "Options:\n" + "\t--stack <required_stack_space>\n" + "\t--priority <priority>\n" + "\t--remove <dest-file>\tRemoves installed application\n" + "\t--force\t\t\tReplaces existing installation\n" + "\t--start <page>\t\tInstalls application at or after <page>\n" + "\t--margin <pages>\tLeave some free space after the kernel (default 16)\n"; + +const char *install_script_text = + "# XIP stacksize=%x priority=%x size=%x\n"; + +const char *install_script_exec = + "exec 0x%x\n"; + + +/**************************************************************************** + * Private functions + ****************************************************************************/ + +int install_getstartpage(int startpage, int pagemargin, int desiredsize) +{ + uint16_t page = 0, stpage = 0xFFFF; + uint16_t pagesize = 0; + int maxlen = -1; + int maxlen_start = 0xFFFF; + int status; + + for (status=0, page=0; status >= 0; page++) { + + status = up_progmem_ispageerased(page); + pagesize = up_progmem_pagesize(page); + + /* Is this beginning of new free space section */ + if (status == 0) { + if (stpage == 0xFFFF) stpage = page; + } + else if (status != 0) { + + if (stpage != 0xFFFF) { + + if ( (page - stpage) > maxlen) { + + if (maxlen==-1) { /* First time found sth? */ + stpage += pagemargin; + maxlen = 0; + } + + if(stpage < startpage) + stpage = startpage; + + if (page > stpage) { + maxlen = page - stpage; + maxlen_start = stpage; + } + + if (maxlen*pagesize >= desiredsize) { + /* printf("Found page at %d ... %d\n", stpage, page); */ + return maxlen_start*pagesize; + } + } + + stpage = 0xFFFF; + } + } + } + + /* Requested space is not available */ + + return -1; +} + + +int install_programflash(int startaddr, const char *source) +{ + int status; + int count; + int totalsize = 0; + char *buf; + FILE *fp; + + if ( (buf = malloc(INSTALL_PROGRAMBLOCKSIZE)) == NULL ) + return -errno; + + if ( (fp=fopen(source, "r")) ) { + do { + count = fread(buf, 1, INSTALL_PROGRAMBLOCKSIZE, fp); + + if ( (status = up_progmem_write(startaddr, buf, count)) < 0) { + totalsize = status; + break; + } + + startaddr += count; + totalsize += count; + } + while(count); + } + else totalsize = -errno; + + fclose(fp); + free(buf); + + return totalsize; +} + + +void install_getscriptname(char *scriptname, const char *progname, const char *destdir) +{ + const char * progonly; + + /* I.e. as /usr/bin */ + strcpy(scriptname, destdir); + + /* extract from i.e. /sdcard/demo -> /demo, together with / */ + progonly = strrchr(progname, '/'); + strcat(scriptname, progonly); +} + + +int install_getprogsize(const char *progname) +{ + struct stat fileinfo; + + if ( stat(progname, &fileinfo) < 0 ) + return -1; + + return fileinfo.st_size; +} + + +int install_alreadyexists(const char *scriptname) +{ + FILE *fp; + + if ( (fp=fopen(scriptname, "r"))==NULL ) + return 0; + + fclose(fp); + return 1; +} + + +int install_createscript(int addr, int stacksize, int progsize, + int priority, const char *scriptname) +{ + FILE *fp; + + if ( (fp=fopen(scriptname, "w+"))==NULL ) + return -errno; + + fprintf(fp, install_script_text, stacksize, priority, progsize); + fprintf(fp, install_script_exec, addr); + + fflush(fp); + fclose(fp); + + return 0; +} + + +int install_getlasthexvalue(FILE *fp, char delimiter) +{ + char buf[128]; + char *p; + + if (fgets(buf, 127, fp)) { + if ( (p = strrchr(buf, delimiter)) ) { + return strtol(p+1, NULL, 16); + } + } + return -1; +} + + +int install_remove(const char *scriptname) +{ + FILE *fp; + int progsize, addr, freedsize; + uint16_t page; + int status = 0; + + /* Parse script */ + + if ( (fp=fopen(scriptname, "r")) ) { + progsize = install_getlasthexvalue(fp,'='); + addr = install_getlasthexvalue(fp,' '); + freedsize = progsize; + } + else return -errno; + + fclose(fp); + + /* Remove pages */ + + if (progsize <= 0 || addr <= 0) + return -EIO; + + do { + if ((page = up_progmem_getpage(addr)) < 0) { + status = -page; + break; + } + + if ( up_progmem_erasepage(page) < 0) { + status = -page; + break; + } + + addr += up_progmem_pagesize(page); + progsize -= up_progmem_pagesize(page); + + } while(progsize > 0); + + if (status < 0) return status; + + /* Remove script file */ + + if (unlink(scriptname) < 0) return -errno; + + return freedsize; +} + + +/**************************************************************************** + * Start + ****************************************************************************/ + +int install_main(int argc, char *argv[]) +{ + int i; + int progsize; + int scrsta; + int stacksize = 4096; + int priority = SCHED_PRIORITY_DEFAULT; + int pagemargin = 16; + int startpage = 0; + int startaddr = 0; + int action = ACTION_INSTALL; + char scriptname[128]; + + /* Supported? */ + + if ( !up_progmem_isuniform() ) { + fprintf(stderr, "Error: install supports uniform organization only.\n"); + return -1; + } + + /* Parse arguments */ + + for (i=1; i<argc; i++) { + if (argv[i][0]=='-' && argv[i][1]=='-' && i<=argc) { + + if (strcmp(argv[i]+2, "stack")==0) { + stacksize = atoi(argv[++i]); + } + else if (strcmp(argv[i]+2, "priority")==0) { + priority = atoi(argv[++i]); + } + else if (strcmp(argv[i]+2, "start")==0) { + startpage = atoi(argv[++i]); + } + else if (strcmp(argv[i]+2, "margin")==0) { + pagemargin = atoi(argv[++i]); + } + else if (strcmp(argv[i]+2, "remove")==0) { + action = ACTION_REMOVE; + } + else if (strcmp(argv[i]+2, "force")==0) { + action = ACTION_REINSTALL; + } + else fprintf(stderr, "Unknown option: %s\n", argv[i]); + } + else break; + } + + /* Do the job */ + + switch(action & 1) { + + case ACTION_REMOVE: + if (i > argc-1) { + action = ACTION_INSUFPARAM; + break; /* are there sufficient parameters */ + } + if ( (scrsta=install_remove(argv[i])) < 0) { + fprintf(stderr, "Could not remove program: %s\n", strerror(-scrsta) ); + return -1; + } + printf("Removed %s and freed %d bytes\n", argv[i], scrsta); + return 0; + + + case ACTION_INSTALL: + if (i > argc-2) { + action = ACTION_INSUFPARAM; + break; /* are there sufficient parameters */ + } + + install_getscriptname(scriptname, argv[i], argv[i+1]); + + // script-exists? + if (install_alreadyexists(scriptname)==1) { + + if (action != ACTION_REINSTALL) { + fprintf(stderr, "Program with that name already exists.\n"); + return -EEXIST; + } + + if ( (scrsta=install_remove(scriptname)) < 0) { + fprintf(stderr, "Could not remove program: %s\n", strerror(-scrsta) ); + return -1; + } + + printf("Replacing %s\n", scriptname); + } + + startaddr = install_getstartpage(startpage, pagemargin, install_getprogsize(argv[i]) ); + if (startpage < 0) { + fprintf(stderr, "Not enough memory\n"); + return -ENOMEM; + } + + if ( (progsize = install_programflash(startaddr, argv[i])) <= 0) { + fprintf(stderr, "Error writing program memory: %s\n" + "Note: Flash pages are not released, so you may try again and program will be\n" + " written in other pages.\n", strerror(-progsize) ); + + return -EIO; + } + if ( (scrsta = install_createscript(startaddr, stacksize, progsize, + priority, scriptname)) < 0) { + fprintf(stderr, "Error writing program script at %s: %s\n", + argv[i+1], strerror(-scrsta) ); + return -EIO; + } + + printf("Installed application of size %d bytes to program memory [%xh - %xh].\n", + progsize, startaddr, startaddr + progsize); + + return 0; + } + + fprintf(stderr, install_help, argv[0], argv[0]); + return -1; +} diff --git a/apps/vsn/Makefile b/apps/vsn/Makefile new file mode 100644 index 000000000..5e9aa843c --- /dev/null +++ b/apps/vsn/Makefile @@ -0,0 +1,71 @@ +############################################################################ +# apps/vsn/Makefile +# +# Copyright (C) 2011 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration + +# Sub-directories + +SUBDIRS = hello poweroff ramtron sdcard sysinfo + +all: nothing +.PHONY: nothing context depend clean distclean + +nothing: + +.context: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir context TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + @touch $@ + +context: .context + +depend: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir depend TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +clean: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir clean TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)"; \ + done + +distclean: clean + @for dir in $(SUBDIRS) ; do \ + $(MAKE) -C $$dir distclean TOPDIR="$(TOPDIR)" APPDIR=$(APPDIR); \ + done + +-include Make.dep + diff --git a/apps/vsn/hello/Makefile b/apps/vsn/hello/Makefile new file mode 100644 index 000000000..23e8890c2 --- /dev/null +++ b/apps/vsn/hello/Makefile @@ -0,0 +1,114 @@ +############################################################################ +# Makefile +# +# Copyright (C) 2011 Uros Platise. All rights reserved. +# Author: Uros Platise <uros.platise@isotel.eu> +# Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TODO, this makefile should run make under the app dirs, instead of +# sourcing the Make.defs! + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +# Hello Application +# TODO: appname can be automatically extracted from the directory name + +APPNAME = hello +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 768 + +ASRCS = +CSRCS = hello.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +# Register application + +.context: + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ + +context: .context + +# Create dependencies + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f .context Make.dep .depend + +-include Make.dep diff --git a/apps/vsn/hello/README.txt b/apps/vsn/hello/README.txt new file mode 100644 index 000000000..531c4d193 --- /dev/null +++ b/apps/vsn/hello/README.txt @@ -0,0 +1,5 @@ + +This application provides Hello Builtin Application skeleton + + Source: NuttX + Date: 13. March 2011 diff --git a/apps/vsn/hello/hello.c b/apps/vsn/hello/hello.c new file mode 100644 index 000000000..fb94d0ea9 --- /dev/null +++ b/apps/vsn/hello/hello.c @@ -0,0 +1,75 @@ +/**************************************************************************** + * hello/hello.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise <uros.platise@isotel.eu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + + +void memtest(void) +{ + char *p; + int i, j; + + for (i=0; i<1000; i++) { + p = malloc(40000); + if (!p) { + printf("No memory\n"); + break; + } + for (j=0; j<40000; j++) p[j] = 0; + free(p); + } +} + + +/** Example of a standalone application + */ +int hello_main(int argc, char *argv[]) +{ + int i; + + printf("Hello Builtin Application\n" + "Found argc=%d arguments and are as follows:\n", argc); + + // note that stdout is bufferred and that fflush() and is called on exit. + fflush(stdout); + + for (i=0; i<argc; i++) + printf("%s\n", argv[i]); + + //memtest(); + + return 0; +} diff --git a/apps/vsn/poweroff/Makefile b/apps/vsn/poweroff/Makefile new file mode 100644 index 000000000..613681010 --- /dev/null +++ b/apps/vsn/poweroff/Makefile @@ -0,0 +1,114 @@ +############################################################################ +# Makefile +# +# Copyright (C) 2011 Uros Platise. All rights reserved. +# Author: Uros Platise <uros.platise@isotel.eu> +# Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TODO, this makefile should run make under the app dirs, instead of +# sourcing the Make.defs! + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +# Hello Application +# TODO: appname can be automatically extracted from the directory name + +APPNAME = poweroff +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 768 + +ASRCS = +CSRCS = poweroff.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +# Register application + +.context: + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ + +context: .context + +# Create dependencies + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f .context Make.dep .depend + +-include Make.dep diff --git a/apps/vsn/poweroff/README.txt b/apps/vsn/poweroff/README.txt new file mode 100644 index 000000000..e02180e5a --- /dev/null +++ b/apps/vsn/poweroff/README.txt @@ -0,0 +1,5 @@ + +This application provides poweroff command + + Source: NuttX + Date: 13. March 2011 diff --git a/apps/vsn/poweroff/poweroff.c b/apps/vsn/poweroff/poweroff.c new file mode 100644 index 000000000..ca3f056e8 --- /dev/null +++ b/apps/vsn/poweroff/poweroff.c @@ -0,0 +1,54 @@ +/**************************************************************************** + * poweroff/poweroff.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise <uros.platise@isotel.eu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include <arch/board/power.h> + +int poweroff_main(int argc, char *argv[]) +{ +/* TODO: + * - replace this by sending general system signal to shutdown, where i.e. nsh + * must issue down script (it may check whether nsh is running before spawning + * a new process with nsh poweroff) + * - wait for some time (~0.5 second for VSN), that SDcard is flashed and synced + * - call poweroff + * + * TODO on boot: + * - if external key is pressed, do not start the nsh! but wait until it is released + * (to get rid of bad mounts of the sdcard etc.) this could be handled in the + * button driver immediately on system boot + */ + board_power_off(); + return 0; +} diff --git a/apps/vsn/ramtron/Makefile b/apps/vsn/ramtron/Makefile new file mode 100644 index 000000000..d91a6ca1b --- /dev/null +++ b/apps/vsn/ramtron/Makefile @@ -0,0 +1,114 @@ +############################################################################ +# Makefile +# +# Copyright (C) 2011 Uros Platise. All rights reserved. +# Author: Uros Platise <uros.platise@isotel.eu> +# Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TODO, this makefile should run make under the app dirs, instead of +# sourcing the Make.defs! + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +# Hello Application +# TODO: appname can be automatically extracted from the directory name + +APPNAME = ramtron +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 1024 + +ASRCS = +CSRCS = ramtron.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +# Register application + +.context: + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ + +context: .context + +# Create dependencies + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f .context Make.dep .depend + +-include Make.dep diff --git a/apps/vsn/ramtron/README.txt b/apps/vsn/ramtron/README.txt new file mode 100644 index 000000000..152774b66 --- /dev/null +++ b/apps/vsn/ramtron/README.txt @@ -0,0 +1,7 @@ + +This application provides RAMTRON tool/lib to start, stop or to perform +RAMTRON custom operations. + + Source: NuttX + Author: Uros Platise + Date: 18. March 2011 diff --git a/apps/vsn/ramtron/ramtron.c b/apps/vsn/ramtron/ramtron.c new file mode 100644 index 000000000..0a648cc30 --- /dev/null +++ b/apps/vsn/ramtron/ramtron.c @@ -0,0 +1,99 @@ +/**************************************************************************** + * ramtron/ramtron.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * + * Authors: Uros Platise <uros.platise@isotel.eu> + * Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <debug.h> +#include <errno.h> +#include <string.h> + +#include <nuttx/spi.h> +#include <nuttx/mtd.h> + +FAR struct mtd_dev_s *ramtron_initialize(FAR struct spi_dev_s *dev); + +int ramtron_start(int spino) +{ + FAR struct spi_dev_s *spi; + FAR struct mtd_dev_s *mtd; + int retval; + + /* Get the SPI port */ + + spi = up_spiinitialize(spino); + if (!spi) + { + printf("RAMTRON: Failed to initialize SPI%d\n", spino); + return -ENODEV; + } + printf("RAMTRON: Initialized SPI%d\n", spino); + + mtd = (struct mtd_dev_s *)ramtron_initialize(spi); + if (!mtd) + { + printf("RAMTRON: Device not found\n"); + return -ENODEV; + } + printf("RAMTRON: FM25V10 of size 128 kB\n"); + //printf("RAMTRON: %s of size %d B\n", ramtron_getpart(mtd), ramtron_getsize(mtd) ); + + retval = ftl_initialize(0, mtd); + printf("RAMTRON: FTL Initialized (returns with %d)\n", retval); + + return OK; +} + + +int ramtron_main(int argc, char *argv[]) +{ + int spino; + + if (argc == 3) { + spino = atoi(argv[2]); + + if (!strcmp(argv[1], "start")) { + return ramtron_start(spino); + } + } + + // todo: write protect + printf("%s: <start> <spino>\n", argv[0]); + return -1; +} diff --git a/apps/vsn/sdcard/Makefile b/apps/vsn/sdcard/Makefile new file mode 100644 index 000000000..d943b909d --- /dev/null +++ b/apps/vsn/sdcard/Makefile @@ -0,0 +1,114 @@ +############################################################################ +# Makefile +# +# Copyright (C) 2011 Uros Platise. All rights reserved. +# Author: Uros Platise <uros.platise@isotel.eu> +# Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TODO, this makefile should run make under the app dirs, instead of +# sourcing the Make.defs! + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +# Hello Application +# TODO: appname can be automatically extracted from the directory name + +APPNAME = sdcard +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 1024 + +ASRCS = +CSRCS = sdcard.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +# Register application + +.context: + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ + +context: .context + +# Create dependencies + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f .context Make.dep .depend + +-include Make.dep diff --git a/apps/vsn/sdcard/README.txt b/apps/vsn/sdcard/README.txt new file mode 100644 index 000000000..332aa26cf --- /dev/null +++ b/apps/vsn/sdcard/README.txt @@ -0,0 +1,7 @@ + +This application provides SDcard tool/lib to start, stop, eject or insert +a memory card. + + Source: NuttX + Author: Uros Platise + Date: 18. March 2011 diff --git a/apps/vsn/sdcard/sdcard.c b/apps/vsn/sdcard/sdcard.c new file mode 100644 index 000000000..47f6c728c --- /dev/null +++ b/apps/vsn/sdcard/sdcard.c @@ -0,0 +1,134 @@ +/**************************************************************************** + * sdcard/sdcard.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * + * Authors: Uros Platise <uros.platise@isotel.eu> + * Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#ifdef CONFIG_STM32_SDIO +# include <nuttx/sdio.h> +# include <nuttx/mmcsd.h> +#endif + +FAR struct sdio_dev_s *sdio_initialize(int slotno); +void sdio_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot); + +// TODO get the structure out from the slot number +static FAR struct sdio_dev_s *sdio = NULL; + +/* Create device device for the SDIO-based MMC/SD block driver */ + +int sdcard_start(int slotno) +{ + int ret; + + /* First, get an instance of the SDIO interface */ + + sdio = sdio_initialize(slotno); + if (!sdio) + { + printf("SDIO: Failed to initialize slot %d\n", slotno); + return -ENODEV; + } + printf("SDIO: Initialized slot %d\n", slotno); + + /* Now bind the SPI interface to the MMC/SD driver */ + + ret = mmcsd_slotinitialize(slotno, sdio); + if (ret != OK) + { + printf("SDIO: Failed to bind to the MMC/SD driver: %d\n", ret); + return ret; + } + printf("SDIO: Successfully bound to the MMC/SD driver\n"); + + /* Then let's guess and say that there is a card in the slot. I need to check to + * see if the VSN board supports a GPIO to detect if there is a card in + * the slot. + */ + sdio_mediachange(sdio, true); + + return OK; +} + + +int sdcard_main(int argc, char *argv[]) +{ + int slotno = 0; + + if (argc >= 2) { + + /* The 3rd argument is expected to be a slot number, if given */ + if (argc==3) + slotno = atoi(argv[2]); + + /* Commands */ + + if (!strcmp(argv[1], "start")) { + return sdcard_start(slotno); + } + else if (!strcmp(argv[1], "stop")) { + fprintf(stderr, "Not implemented yet\n"); + } + else if (!strcmp(argv[1], "insert")) { + if (sdio) { + sdio_mediachange(sdio, true); + return OK; + } + } + else if (!strcmp(argv[1], "eject")) { + if (sdio) { + sdio_mediachange(sdio, false); + return OK; + } + } + else if (!strcmp(argv[1], "status")) { + printf("SDcard #%d Status:\n", slotno); +#ifndef CONFIG_MMCSD_HAVECARDDETECT + printf("\t - Without SDcard detect capability\n"); +#endif + return 0; + } + } + + printf("%s: <start|stop|insert|eject|status> {slotno}\n", argv[0]); + return -1; +} diff --git a/apps/vsn/sysinfo/Makefile b/apps/vsn/sysinfo/Makefile new file mode 100644 index 000000000..f0aac6df2 --- /dev/null +++ b/apps/vsn/sysinfo/Makefile @@ -0,0 +1,114 @@ +############################################################################ +# Makefile +# +# Copyright (C) 2011 Uros Platise. All rights reserved. +# Author: Uros Platise <uros.platise@isotel.eu> +# Gregory Nutt <spudmonkey@racsa.co.cr> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# TODO, this makefile should run make under the app dirs, instead of +# sourcing the Make.defs! + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ifeq ($(WINTOOL),y) +INCDIROPT = -w +endif + +# Hello Application +# TODO: appname can be automatically extracted from the directory name + +APPNAME = sysinfo +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 768 + +ASRCS = +CSRCS = sysinfo.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +# Register application + +.context: + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + @touch $@ + +context: .context + +# Create dependencies + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f .context Make.dep .depend + +-include Make.dep diff --git a/apps/vsn/sysinfo/README.txt b/apps/vsn/sysinfo/README.txt new file mode 100644 index 000000000..3792f4a59 --- /dev/null +++ b/apps/vsn/sysinfo/README.txt @@ -0,0 +1,6 @@ + +This application provides access to System Information + + Source: NuttX + Date: 15. April 2011 + Author: Uros Platise <uros.platise@isotel.eu> diff --git a/apps/vsn/sysinfo/sysinfo.c b/apps/vsn/sysinfo/sysinfo.c new file mode 100644 index 000000000..8625f9db7 --- /dev/null +++ b/apps/vsn/sysinfo/sysinfo.c @@ -0,0 +1,69 @@ +/**************************************************************************** + * sysinfo/sysinfo.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise <uros.platise@isotel.eu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** \file + * \brief System Information + * \author Uros Platise + * + * Collects and reports system information. + * + * \todo Gather information also from low-level devices, kernel/sched, clock, + * and further reporting as: sysinfo rtc, or sysinfo sched, ... with + * sysinfo help to report all of the options. + * + **/ + +#include <nuttx/config.h> +#include <nuttx/version.h> +#include <time.h> + +#include <stdio.h> +#include <stdlib.h> + + +int sysinfo_main(int argc, char *argv[]) +{ + printf("System Information:\n"); + + printf("\tNuttX Version:\t" CONFIG_VERSION_STRING " Build: %d\n", CONFIG_VERSION_BUILD); + + printf("\tSystem Time:\t%d [s] UTC " +#ifdef CONFIG_RTC + "Hardware RTC Support" +#endif + "\n", time(NULL) ); + + return 0; +} |