aboutsummaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-09-17 18:18:44 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-09-17 18:18:44 +0000
commit57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff (patch)
tree25d07d14e920d31c0b1947c9ca586f2a01fc32d8 /apps
downloadpx4-firmware-57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff.tar.gz
px4-firmware-57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff.tar.bz2
px4-firmware-57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff.zip
Resync new repository with old repo r5166
git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5153 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'apps')
-rw-r--r--apps/ChangeLog.txt335
-rw-r--r--apps/Kconfig36
-rw-r--r--apps/Make.defs41
-rw-r--r--apps/Makefile173
-rw-r--r--apps/README.txt211
-rw-r--r--apps/examples/Kconfig208
-rw-r--r--apps/examples/Make.defs231
-rw-r--r--apps/examples/Makefile131
-rw-r--r--apps/examples/README.txt1694
-rw-r--r--apps/examples/adc/Kconfig13
-rw-r--r--apps/examples/adc/Makefile105
-rw-r--r--apps/examples/adc/adc.h125
-rw-r--r--apps/examples/adc/adc_main.c359
-rw-r--r--apps/examples/buttons/Kconfig13
-rw-r--r--apps/examples/buttons/Makefile105
-rw-r--r--apps/examples/buttons/buttons_main.c499
-rw-r--r--apps/examples/can/Kconfig14
-rw-r--r--apps/examples/can/Makefile105
-rw-r--r--apps/examples/can/can.h131
-rw-r--r--apps/examples/can/can_main.c301
-rw-r--r--apps/examples/cdcacm/Kconfig14
-rw-r--r--apps/examples/cdcacm/Makefile109
-rw-r--r--apps/examples/cdcacm/cdcacm.h165
-rw-r--r--apps/examples/cdcacm/cdcacm_main.c147
-rw-r--r--apps/examples/composite/Kconfig14
-rw-r--r--apps/examples/composite/Makefile111
-rw-r--r--apps/examples/composite/composite.h259
-rw-r--r--apps/examples/composite/composite_main.c851
-rw-r--r--apps/examples/dhcpd/Kconfig14
-rw-r--r--apps/examples/dhcpd/Makefile106
-rw-r--r--apps/examples/dhcpd/Makefile.host62
-rw-r--r--apps/examples/dhcpd/host.c58
-rw-r--r--apps/examples/dhcpd/target.c130
-rw-r--r--apps/examples/discover/Kconfig45
-rw-r--r--apps/examples/discover/Makefile106
-rw-r--r--apps/examples/discover/discover_main.c188
-rw-r--r--apps/examples/ftpc/Kconfig13
-rw-r--r--apps/examples/ftpc/Makefile105
-rw-r--r--apps/examples/ftpc/ftpc.h112
-rw-r--r--apps/examples/ftpc/ftpc_cmds.c398
-rw-r--r--apps/examples/ftpc/ftpc_main.c455
-rw-r--r--apps/examples/ftpd/Kconfig13
-rw-r--r--apps/examples/ftpd/Makefile101
-rw-r--r--apps/examples/ftpd/ftpd.h157
-rw-r--r--apps/examples/ftpd/ftpd_main.c292
-rw-r--r--apps/examples/hello/Kconfig13
-rw-r--r--apps/examples/hello/Makefile105
-rw-r--r--apps/examples/hello/hello_main.c64
-rw-r--r--apps/examples/helloxx/Kconfig13
-rw-r--r--apps/examples/helloxx/Makefile122
-rw-r--r--apps/examples/helloxx/helloxx_main.cxx165
-rw-r--r--apps/examples/hidkbd/Kconfig13
-rw-r--r--apps/examples/hidkbd/Makefile93
-rw-r--r--apps/examples/hidkbd/hidkbd_main.c231
-rw-r--r--apps/examples/igmp/Kconfig13
-rw-r--r--apps/examples/igmp/Makefile93
-rw-r--r--apps/examples/igmp/igmp.c142
-rw-r--r--apps/examples/igmp/igmp.h61
-rw-r--r--apps/examples/lcdrw/Kconfig13
-rw-r--r--apps/examples/lcdrw/Makefile105
-rw-r--r--apps/examples/lcdrw/lcdrw_main.c253
-rw-r--r--apps/examples/mm/Kconfig13
-rw-r--r--apps/examples/mm/Makefile93
-rw-r--r--apps/examples/mm/mm_main.c300
-rw-r--r--apps/examples/modbus/Kconfig13
-rw-r--r--apps/examples/modbus/Makefile105
-rw-r--r--apps/examples/modbus/modbus_main.c550
-rw-r--r--apps/examples/mount/Kconfig13
-rw-r--r--apps/examples/mount/Makefile93
-rw-r--r--apps/examples/mount/mount.h96
-rw-r--r--apps/examples/mount/mount_main.c754
-rw-r--r--apps/examples/mount/ramdisk.c141
-rw-r--r--apps/examples/nettest/Kconfig13
-rw-r--r--apps/examples/nettest/Makefile142
-rw-r--r--apps/examples/nettest/host.c63
-rw-r--r--apps/examples/nettest/nettest.c109
-rw-r--r--apps/examples/nettest/nettest.h95
-rw-r--r--apps/examples/nettest/nettest_client.c210
-rw-r--r--apps/examples/nettest/nettest_server.c245
-rw-r--r--apps/examples/nsh/Kconfig15
-rw-r--r--apps/examples/nsh/Makefile93
-rw-r--r--apps/examples/nsh/nsh_main.c136
-rw-r--r--apps/examples/null/Kconfig13
-rw-r--r--apps/examples/null/Makefile93
-rw-r--r--apps/examples/null/null_main.c67
-rw-r--r--apps/examples/nx/Kconfig13
-rw-r--r--apps/examples/nx/Makefile108
-rw-r--r--apps/examples/nx/nx_events.c337
-rw-r--r--apps/examples/nx/nx_internal.h317
-rw-r--r--apps/examples/nx/nx_kbdin.c467
-rw-r--r--apps/examples/nx/nx_main.c900
-rw-r--r--apps/examples/nx/nx_server.c152
-rw-r--r--apps/examples/nxconsole/Kconfig13
-rw-r--r--apps/examples/nxconsole/Makefile93
-rw-r--r--apps/examples/nxconsole/nxcon_internal.h310
-rw-r--r--apps/examples/nxconsole/nxcon_main.c412
-rw-r--r--apps/examples/nxconsole/nxcon_server.c189
-rw-r--r--apps/examples/nxconsole/nxcon_toolbar.c172
-rw-r--r--apps/examples/nxconsole/nxcon_wndo.c208
-rw-r--r--apps/examples/nxffs/Kconfig13
-rw-r--r--apps/examples/nxffs/Makefile93
-rw-r--r--apps/examples/nxffs/nxffs_main.c947
-rw-r--r--apps/examples/nxflat/Kconfig13
-rw-r--r--apps/examples/nxflat/Makefile98
-rw-r--r--apps/examples/nxflat/nxflat_main.c224
-rw-r--r--apps/examples/nxflat/tests/Makefile103
-rw-r--r--apps/examples/nxflat/tests/errno/Makefile78
-rw-r--r--apps/examples/nxflat/tests/errno/errno.c83
-rw-r--r--apps/examples/nxflat/tests/hello++/Makefile180
-rw-r--r--apps/examples/nxflat/tests/hello++/hello++1.cpp60
-rw-r--r--apps/examples/nxflat/tests/hello++/hello++2.cpp123
-rw-r--r--apps/examples/nxflat/tests/hello++/hello++3.cpp132
-rw-r--r--apps/examples/nxflat/tests/hello++/hello++4.cpp150
-rw-r--r--apps/examples/nxflat/tests/hello/Makefile78
-rw-r--r--apps/examples/nxflat/tests/hello/hello.c78
-rw-r--r--apps/examples/nxflat/tests/longjmp/Makefile78
-rw-r--r--apps/examples/nxflat/tests/longjmp/longjmp.c128
-rwxr-xr-xapps/examples/nxflat/tests/mkdirlist.sh35
-rwxr-xr-xapps/examples/nxflat/tests/mksymtab.sh39
-rw-r--r--apps/examples/nxflat/tests/mutex/Makefile78
-rw-r--r--apps/examples/nxflat/tests/mutex/mutex.c149
-rw-r--r--apps/examples/nxflat/tests/pthread/Makefile78
-rw-r--r--apps/examples/nxflat/tests/pthread/pthread.c143
-rw-r--r--apps/examples/nxflat/tests/signal/Makefile78
-rw-r--r--apps/examples/nxflat/tests/signal/signal.c308
-rw-r--r--apps/examples/nxflat/tests/struct/Makefile80
-rw-r--r--apps/examples/nxflat/tests/struct/struct.h89
-rw-r--r--apps/examples/nxflat/tests/struct/struct_dummy.c65
-rw-r--r--apps/examples/nxflat/tests/struct/struct_main.c109
-rw-r--r--apps/examples/nxflat/tests/task/Makefile79
-rw-r--r--apps/examples/nxflat/tests/task/task.c143
-rw-r--r--apps/examples/nxhello/Kconfig13
-rw-r--r--apps/examples/nxhello/Makefile105
-rw-r--r--apps/examples/nxhello/nxhello.h196
-rw-r--r--apps/examples/nxhello/nxhello_bkgd.c443
-rw-r--r--apps/examples/nxhello/nxhello_main.c286
-rw-r--r--apps/examples/nximage/Kconfig13
-rw-r--r--apps/examples/nximage/Makefile105
-rw-r--r--apps/examples/nximage/nximage.h219
-rw-r--r--apps/examples/nximage/nximage_bitmap.c3711
-rw-r--r--apps/examples/nximage/nximage_bkgd.c397
-rw-r--r--apps/examples/nximage/nximage_main.c281
-rw-r--r--apps/examples/nxlines/Kconfig13
-rw-r--r--apps/examples/nxlines/Makefile105
-rw-r--r--apps/examples/nxlines/nxlines.h197
-rw-r--r--apps/examples/nxlines/nxlines_bkgd.c335
-rw-r--r--apps/examples/nxlines/nxlines_main.c272
-rw-r--r--apps/examples/nxtext/Kconfig13
-rw-r--r--apps/examples/nxtext/Makefile109
-rw-r--r--apps/examples/nxtext/nxtext_bkgd.c467
-rw-r--r--apps/examples/nxtext/nxtext_internal.h366
-rw-r--r--apps/examples/nxtext/nxtext_main.c504
-rw-r--r--apps/examples/nxtext/nxtext_popup.c408
-rw-r--r--apps/examples/nxtext/nxtext_putc.c598
-rw-r--r--apps/examples/nxtext/nxtext_server.c194
-rw-r--r--apps/examples/ostest/Kconfig42
-rw-r--r--apps/examples/ostest/Makefile149
-rw-r--r--apps/examples/ostest/barrier.c208
-rw-r--r--apps/examples/ostest/cancel.c333
-rw-r--r--apps/examples/ostest/cond.c294
-rw-r--r--apps/examples/ostest/dev_null.c92
-rw-r--r--apps/examples/ostest/fpu.c344
-rw-r--r--apps/examples/ostest/mqueue.c394
-rw-r--r--apps/examples/ostest/mutex.c142
-rw-r--r--apps/examples/ostest/ostest.h178
-rw-r--r--apps/examples/ostest/ostest_main.c522
-rw-r--r--apps/examples/ostest/posixtimer.c262
-rw-r--r--apps/examples/ostest/prioinherit.c559
-rw-r--r--apps/examples/ostest/rmutex.c166
-rw-r--r--apps/examples/ostest/roundrobin.c232
-rw-r--r--apps/examples/ostest/sem.c246
-rw-r--r--apps/examples/ostest/sighand.c267
-rw-r--r--apps/examples/ostest/timedmqueue.c387
-rw-r--r--apps/examples/ostest/timedwait.c195
-rw-r--r--apps/examples/pashello/Kconfig13
-rw-r--r--apps/examples/pashello/Makefile93
-rw-r--r--apps/examples/pashello/README.txt34
-rw-r--r--apps/examples/pashello/device.c110
-rw-r--r--apps/examples/pashello/hello.h23
-rw-r--r--apps/examples/pashello/hello.pas5
-rw-r--r--apps/examples/pashello/hello.pexbin0 -> 232 bytes
-rwxr-xr-xapps/examples/pashello/mkhello.sh141
-rw-r--r--apps/examples/pashello/pashello.c133
-rw-r--r--apps/examples/pashello/pashello.h55
-rw-r--r--apps/examples/pipe/Kconfig13
-rw-r--r--apps/examples/pipe/Makefile93
-rw-r--r--apps/examples/pipe/interlock_test.c224
-rw-r--r--apps/examples/pipe/pipe.h74
-rw-r--r--apps/examples/pipe/pipe_main.c189
-rw-r--r--apps/examples/pipe/redirect_test.c326
-rw-r--r--apps/examples/pipe/transfer_test.c242
-rw-r--r--apps/examples/poll/Kconfig13
-rw-r--r--apps/examples/poll/Makefile94
-rw-r--r--apps/examples/poll/Makefile.host54
-rw-r--r--apps/examples/poll/host.c171
-rw-r--r--apps/examples/poll/net_listener.c428
-rw-r--r--apps/examples/poll/net_reader.c317
-rw-r--r--apps/examples/poll/poll_internal.h128
-rw-r--r--apps/examples/poll/poll_listener.c262
-rw-r--r--apps/examples/poll/poll_main.c221
-rw-r--r--apps/examples/poll/select_listener.c193
-rw-r--r--apps/examples/pwm/Kconfig48
-rw-r--r--apps/examples/pwm/Makefile103
-rw-r--r--apps/examples/pwm/pwm.h134
-rw-r--r--apps/examples/pwm/pwm_main.c394
-rw-r--r--apps/examples/qencoder/Kconfig13
-rw-r--r--apps/examples/qencoder/Makefile105
-rw-r--r--apps/examples/qencoder/qe.h134
-rw-r--r--apps/examples/qencoder/qe_main.c362
-rw-r--r--apps/examples/rgmp/Kconfig13
-rw-r--r--apps/examples/rgmp/Makefile93
-rw-r--r--apps/examples/rgmp/rgmp_main.c66
-rw-r--r--apps/examples/romfs/Kconfig13
-rw-r--r--apps/examples/romfs/Makefile111
-rw-r--r--apps/examples/romfs/romfs_main.c498
-rw-r--r--apps/examples/romfs/romfs_testdir.h89
-rw-r--r--apps/examples/romfs/testdir.tar.gzbin0 -> 387 bytes
-rw-r--r--apps/examples/romfs/testdir.txt105
-rw-r--r--apps/examples/sendmail/Kconfig13
-rw-r--r--apps/examples/sendmail/Makefile96
-rw-r--r--apps/examples/sendmail/Makefile.host77
-rw-r--r--apps/examples/sendmail/host.c103
-rw-r--r--apps/examples/sendmail/hostdefs.h69
-rw-r--r--apps/examples/sendmail/target.c157
-rw-r--r--apps/examples/serloop/Kconfig13
-rw-r--r--apps/examples/serloop/Makefile95
-rw-r--r--apps/examples/serloop/serloop_main.c100
-rw-r--r--apps/examples/telnetd/Kconfig13
-rw-r--r--apps/examples/telnetd/Makefile105
-rw-r--r--apps/examples/telnetd/README.txt8
-rw-r--r--apps/examples/telnetd/shell.c255
-rw-r--r--apps/examples/telnetd/shell.h92
-rw-r--r--apps/examples/thttpd/Kconfig13
-rw-r--r--apps/examples/thttpd/Makefile98
-rw-r--r--apps/examples/thttpd/content/Makefile104
-rw-r--r--apps/examples/thttpd/content/hello/Makefile78
-rw-r--r--apps/examples/thttpd/content/hello/hello.c79
-rw-r--r--apps/examples/thttpd/content/index.html30
-rwxr-xr-xapps/examples/thttpd/content/mksymtab.sh39
-rw-r--r--apps/examples/thttpd/content/netstat/Makefile78
-rw-r--r--apps/examples/thttpd/content/netstat/netstat.c134
-rw-r--r--apps/examples/thttpd/content/style.css80
-rw-r--r--apps/examples/thttpd/content/tasks/Makefile78
-rw-r--r--apps/examples/thttpd/content/tasks/tasks.c176
-rw-r--r--apps/examples/thttpd/thttpd_main.c267
-rw-r--r--apps/examples/tiff/Kconfig13
-rw-r--r--apps/examples/tiff/Makefile106
-rw-r--r--apps/examples/tiff/tiff_main.c168
-rw-r--r--apps/examples/touchscreen/Kconfig13
-rw-r--r--apps/examples/touchscreen/Makefile105
-rw-r--r--apps/examples/touchscreen/tc.h113
-rw-r--r--apps/examples/touchscreen/tc_main.c208
-rw-r--r--apps/examples/udp/Kconfig13
-rw-r--r--apps/examples/udp/Makefile124
-rw-r--r--apps/examples/udp/host.c63
-rw-r--r--apps/examples/udp/target.c91
-rw-r--r--apps/examples/udp/udp-client.c133
-rw-r--r--apps/examples/udp/udp-internal.h90
-rw-r--r--apps/examples/udp/udp-server.c173
-rw-r--r--apps/examples/uip/Kconfig13
-rw-r--r--apps/examples/uip/Makefile98
-rw-r--r--apps/examples/uip/cgi.c108
-rw-r--r--apps/examples/uip/cgi.h43
-rw-r--r--apps/examples/uip/httpd-fs/404.html8
-rw-r--r--apps/examples/uip/httpd-fs/fade.pngbin0 -> 196 bytes
-rw-r--r--apps/examples/uip/httpd-fs/files.shtml31
-rw-r--r--apps/examples/uip/httpd-fs/footer.html3
-rw-r--r--apps/examples/uip/httpd-fs/header.html16
-rw-r--r--apps/examples/uip/httpd-fs/index.shtml10
-rw-r--r--apps/examples/uip/httpd-fs/stats.shtml31
-rw-r--r--apps/examples/uip/httpd-fs/style.css92
-rw-r--r--apps/examples/uip/httpd-fs/tcp.shtml5
-rw-r--r--apps/examples/uip/uip_main.c210
-rw-r--r--apps/examples/usbserial/Kconfig13
-rw-r--r--apps/examples/usbserial/Makefile95
-rw-r--r--apps/examples/usbserial/Makefile.host67
-rw-r--r--apps/examples/usbserial/host.c297
-rw-r--r--apps/examples/usbserial/usbserial_main.c467
-rw-r--r--apps/examples/usbstorage/Kconfig136
-rw-r--r--apps/examples/usbstorage/Makefile111
-rw-r--r--apps/examples/usbstorage/usbmsc.h166
-rw-r--r--apps/examples/usbstorage/usbmsc_main.c588
-rw-r--r--apps/examples/usbterm/Kconfig13
-rw-r--r--apps/examples/usbterm/Makefile106
-rw-r--r--apps/examples/usbterm/usbterm.h181
-rw-r--r--apps/examples/usbterm/usbterm_main.c376
-rw-r--r--apps/examples/watchdog/Kconfig40
-rw-r--r--apps/examples/watchdog/Makefile103
-rw-r--r--apps/examples/watchdog/watchdog.h120
-rw-r--r--apps/examples/watchdog/watchdog_main.c357
-rw-r--r--apps/examples/wget/Kconfig13
-rw-r--r--apps/examples/wget/Makefile95
-rw-r--r--apps/examples/wget/Makefile.host77
-rw-r--r--apps/examples/wget/host.c100
-rw-r--r--apps/examples/wget/hostdefs.h69
-rw-r--r--apps/examples/wget/target.c150
-rw-r--r--apps/examples/wlan/Kconfig13
-rw-r--r--apps/examples/wlan/Makefile95
-rw-r--r--apps/examples/wlan/wlan_main.c306
-rw-r--r--apps/examples/xmlrpc/Kconfig46
-rw-r--r--apps/examples/xmlrpc/Makefile106
-rw-r--r--apps/examples/xmlrpc/calls.c122
-rw-r--r--apps/examples/xmlrpc/xmlrpc_main.c419
-rw-r--r--apps/graphics/Kconfig13
-rw-r--r--apps/graphics/Make.defs40
-rw-r--r--apps/graphics/Makefile72
-rw-r--r--apps/graphics/tiff/Makefile93
-rw-r--r--apps/graphics/tiff/README.txt15
-rw-r--r--apps/graphics/tiff/tiff_addstrip.c239
-rw-r--r--apps/graphics/tiff/tiff_finalize.c439
-rw-r--r--apps/graphics/tiff/tiff_initialize.c910
-rw-r--r--apps/graphics/tiff/tiff_internal.h211
-rw-r--r--apps/graphics/tiff/tiff_utils.c381
-rw-r--r--apps/include/apps.h149
-rw-r--r--apps/include/ftpc.h225
-rw-r--r--apps/include/modbus/mb.h418
-rw-r--r--apps/include/modbus/mbframe.h87
-rw-r--r--apps/include/modbus/mbfunc.h80
-rw-r--r--apps/include/modbus/mbport.h132
-rw-r--r--apps/include/modbus/mbproto.h83
-rw-r--r--apps/include/modbus/mbutils.h108
-rw-r--r--apps/include/netutils/dhcpc.h85
-rw-r--r--apps/include/netutils/dhcpd.h71
-rw-r--r--apps/include/netutils/discover.h58
-rw-r--r--apps/include/netutils/ftpd.h217
-rw-r--r--apps/include/netutils/httpd.h185
-rw-r--r--apps/include/netutils/ipmsfilter.h101
-rw-r--r--apps/include/netutils/resolv.h82
-rw-r--r--apps/include/netutils/smtp.h78
-rw-r--r--apps/include/netutils/telnetd.h127
-rw-r--r--apps/include/netutils/tftp.h73
-rw-r--r--apps/include/netutils/thttpd.h101
-rw-r--r--apps/include/netutils/uiplib.h143
-rw-r--r--apps/include/netutils/webclient.h149
-rw-r--r--apps/include/netutils/xmlrpc.h123
-rw-r--r--apps/include/nsh.h121
-rw-r--r--apps/include/readline.h100
-rw-r--r--apps/include/tiff.h465
-rw-r--r--apps/interpreters/Kconfig21
-rw-r--r--apps/interpreters/Make.defs43
-rw-r--r--apps/interpreters/Makefile70
-rw-r--r--apps/interpreters/README.txt67
-rw-r--r--apps/interpreters/ficl/Kconfig16
-rw-r--r--apps/interpreters/ficl/Makefile118
-rw-r--r--apps/interpreters/ficl/README.txt42
-rwxr-xr-xapps/interpreters/ficl/configure.sh47
-rw-r--r--apps/interpreters/ficl/src/nuttx.c65
-rw-r--r--apps/interpreters/ficl/src/nuttx.h19
-rw-r--r--apps/modbus/Kconfig143
-rw-r--r--apps/modbus/Make.defs40
-rw-r--r--apps/modbus/Makefile116
-rw-r--r--apps/modbus/README.txt117
-rw-r--r--apps/modbus/ascii/Make.defs44
-rw-r--r--apps/modbus/ascii/mbascii.c487
-rw-r--r--apps/modbus/ascii/mbascii.h56
-rw-r--r--apps/modbus/functions/Make.defs41
-rw-r--r--apps/modbus/functions/mbfunccoils.c270
-rw-r--r--apps/modbus/functions/mbfuncdiag.c29
-rw-r--r--apps/modbus/functions/mbfuncdisc.c123
-rw-r--r--apps/modbus/functions/mbfuncholding.c308
-rw-r--r--apps/modbus/functions/mbfuncinput.c122
-rw-r--r--apps/modbus/functions/mbfuncother.c88
-rw-r--r--apps/modbus/functions/mbutils.c143
-rw-r--r--apps/modbus/mb.c415
-rw-r--r--apps/modbus/nuttx/Make.defs40
-rw-r--r--apps/modbus/nuttx/port.h77
-rw-r--r--apps/modbus/nuttx/portevent.c76
-rw-r--r--apps/modbus/nuttx/portother.c106
-rw-r--r--apps/modbus/nuttx/portserial.c369
-rw-r--r--apps/modbus/nuttx/porttimer.c102
-rw-r--r--apps/modbus/rtu/Make.defs44
-rw-r--r--apps/modbus/rtu/mbcrc.c98
-rw-r--r--apps/modbus/rtu/mbcrc.h36
-rw-r--r--apps/modbus/rtu/mbrtu.c357
-rw-r--r--apps/modbus/rtu/mbrtu.h51
-rw-r--r--apps/modbus/tcp/Make.defs44
-rw-r--r--apps/modbus/tcp/mbtcp.c159
-rw-r--r--apps/modbus/tcp/mbtcp.h53
-rw-r--r--apps/namedapp/Kconfig15
-rw-r--r--apps/namedapp/Make.defs40
-rw-r--r--apps/namedapp/Makefile106
-rw-r--r--apps/namedapp/binfs.c596
-rw-r--r--apps/namedapp/exec_namedapp.c187
-rw-r--r--apps/namedapp/namedapp.c96
-rw-r--r--apps/namedapp/namedapp.h78
-rw-r--r--apps/netutils/Kconfig62
-rw-r--r--apps/netutils/Make.defs91
-rw-r--r--apps/netutils/Makefile66
-rw-r--r--apps/netutils/README.txt112
-rw-r--r--apps/netutils/dhcpc/Kconfig13
-rw-r--r--apps/netutils/dhcpc/Makefile97
-rw-r--r--apps/netutils/dhcpc/dhcpc.c607
-rw-r--r--apps/netutils/dhcpd/Kconfig13
-rw-r--r--apps/netutils/dhcpd/Makefile97
-rw-r--r--apps/netutils/dhcpd/dhcpd.c1433
-rw-r--r--apps/netutils/discover/Kconfig40
-rw-r--r--apps/netutils/discover/Makefile100
-rw-r--r--apps/netutils/discover/README.txt9
-rw-r--r--apps/netutils/discover/discover.c456
-rw-r--r--apps/netutils/ftpc/Kconfig13
-rw-r--r--apps/netutils/ftpc/Makefile113
-rw-r--r--apps/netutils/ftpc/README.txt81
-rw-r--r--apps/netutils/ftpc/ftpc_cdup.c87
-rw-r--r--apps/netutils/ftpc/ftpc_chdir.c91
-rw-r--r--apps/netutils/ftpc/ftpc_chmod.c107
-rw-r--r--apps/netutils/ftpc/ftpc_cmd.c238
-rw-r--r--apps/netutils/ftpc/ftpc_config.h72
-rw-r--r--apps/netutils/ftpc/ftpc_connect.c250
-rw-r--r--apps/netutils/ftpc/ftpc_disconnect.c102
-rw-r--r--apps/netutils/ftpc/ftpc_filesize.c112
-rw-r--r--apps/netutils/ftpc/ftpc_filetime.c134
-rw-r--r--apps/netutils/ftpc/ftpc_getfile.c429
-rw-r--r--apps/netutils/ftpc/ftpc_getreply.c268
-rw-r--r--apps/netutils/ftpc/ftpc_help.c100
-rw-r--r--apps/netutils/ftpc/ftpc_idle.c122
-rw-r--r--apps/netutils/ftpc/ftpc_internal.h281
-rw-r--r--apps/netutils/ftpc/ftpc_listdir.c412
-rw-r--r--apps/netutils/ftpc/ftpc_login.c214
-rw-r--r--apps/netutils/ftpc/ftpc_mkdir.c105
-rw-r--r--apps/netutils/ftpc/ftpc_noop.c85
-rw-r--r--apps/netutils/ftpc/ftpc_putfile.c481
-rw-r--r--apps/netutils/ftpc/ftpc_quit.c92
-rw-r--r--apps/netutils/ftpc/ftpc_rename.c134
-rw-r--r--apps/netutils/ftpc/ftpc_response.c84
-rw-r--r--apps/netutils/ftpc/ftpc_rmdir.c103
-rw-r--r--apps/netutils/ftpc/ftpc_rpwd.c151
-rw-r--r--apps/netutils/ftpc/ftpc_socket.c370
-rw-r--r--apps/netutils/ftpc/ftpc_transfer.c517
-rw-r--r--apps/netutils/ftpc/ftpc_unlink.c96
-rw-r--r--apps/netutils/ftpc/ftpc_utils.c266
-rw-r--r--apps/netutils/ftpd/Kconfig13
-rw-r--r--apps/netutils/ftpd/Makefile97
-rw-r--r--apps/netutils/ftpd/ftpd.c4398
-rw-r--r--apps/netutils/ftpd/ftpd.h199
-rw-r--r--apps/netutils/resolv/Kconfig17
-rw-r--r--apps/netutils/resolv/Makefile97
-rw-r--r--apps/netutils/resolv/resolv.c440
-rw-r--r--apps/netutils/smtp/Kconfig13
-rw-r--r--apps/netutils/smtp/Makefile97
-rw-r--r--apps/netutils/smtp/smtp.c376
-rw-r--r--apps/netutils/telnetd/Kconfig13
-rw-r--r--apps/netutils/telnetd/Makefile97
-rw-r--r--apps/netutils/telnetd/README.txt4
-rw-r--r--apps/netutils/telnetd/telnetd.h115
-rw-r--r--apps/netutils/telnetd/telnetd_daemon.c352
-rw-r--r--apps/netutils/telnetd/telnetd_driver.c813
-rw-r--r--apps/netutils/tftpc/Kconfig13
-rw-r--r--apps/netutils/tftpc/Makefile99
-rw-r--r--apps/netutils/tftpc/tftpc_get.c337
-rw-r--r--apps/netutils/tftpc/tftpc_internal.h173
-rw-r--r--apps/netutils/tftpc/tftpc_packets.c330
-rw-r--r--apps/netutils/tftpc/tftpc_put.c485
-rw-r--r--apps/netutils/thttpd/Kconfig240
-rw-r--r--apps/netutils/thttpd/Makefile129
-rw-r--r--apps/netutils/thttpd/cgi-src/Makefile140
-rw-r--r--apps/netutils/thttpd/cgi-src/phf.c77
-rw-r--r--apps/netutils/thttpd/cgi-src/redirect.c269
-rw-r--r--apps/netutils/thttpd/cgi-src/ssi.c957
-rw-r--r--apps/netutils/thttpd/config.h253
-rw-r--r--apps/netutils/thttpd/fdwatch.c371
-rw-r--r--apps/netutils/thttpd/fdwatch.h111
-rw-r--r--apps/netutils/thttpd/libhttpd.c3525
-rw-r--r--apps/netutils/thttpd/libhttpd.h342
-rw-r--r--apps/netutils/thttpd/mime_types.h279
-rw-r--r--apps/netutils/thttpd/tdate_parse.c341
-rw-r--r--apps/netutils/thttpd/tdate_parse.h41
-rw-r--r--apps/netutils/thttpd/thttpd.c861
-rw-r--r--apps/netutils/thttpd/thttpd_alloc.c199
-rw-r--r--apps/netutils/thttpd/thttpd_alloc.h78
-rw-r--r--apps/netutils/thttpd/thttpd_cgi.c1081
-rw-r--r--apps/netutils/thttpd/thttpd_cgi.h61
-rw-r--r--apps/netutils/thttpd/thttpd_strings.c179
-rw-r--r--apps/netutils/thttpd/thttpd_strings.h123
-rw-r--r--apps/netutils/thttpd/timers.c365
-rw-r--r--apps/netutils/thttpd/timers.h136
-rw-r--r--apps/netutils/uiplib/Kconfig13
-rw-r--r--apps/netutils/uiplib/Makefile112
-rw-r--r--apps/netutils/uiplib/uip_gethostaddr.c105
-rw-r--r--apps/netutils/uiplib/uip_getmacaddr.c104
-rw-r--r--apps/netutils/uiplib/uip_ipmsfilter.c116
-rw-r--r--apps/netutils/uiplib/uip_listenon.c131
-rw-r--r--apps/netutils/uiplib/uip_parsehttpurl.c149
-rw-r--r--apps/netutils/uiplib/uip_server.c150
-rw-r--r--apps/netutils/uiplib/uip_setdraddr.c116
-rw-r--r--apps/netutils/uiplib/uip_sethostaddr.c116
-rw-r--r--apps/netutils/uiplib/uip_setmacaddr.c114
-rw-r--r--apps/netutils/uiplib/uip_setnetmask.c115
-rw-r--r--apps/netutils/uiplib/uiplib.c95
-rw-r--r--apps/netutils/webclient/Kconfig13
-rw-r--r--apps/netutils/webclient/Makefile97
-rw-r--r--apps/netutils/webclient/webclient.c584
-rw-r--r--apps/netutils/webserver/Kconfig92
-rw-r--r--apps/netutils/webserver/Makefile104
-rw-r--r--apps/netutils/webserver/httpd.c635
-rw-r--r--apps/netutils/webserver/httpd.h79
-rw-r--r--apps/netutils/webserver/httpd_cgi.c88
-rw-r--r--apps/netutils/webserver/httpd_cgi.h55
-rw-r--r--apps/netutils/webserver/httpd_fs.c153
-rw-r--r--apps/netutils/webserver/httpd_mmap.c143
-rw-r--r--apps/netutils/webserver/httpd_sendfile.c128
-rw-r--r--apps/netutils/xmlrpc/Kconfig23
-rw-r--r--apps/netutils/xmlrpc/Makefile99
-rw-r--r--apps/netutils/xmlrpc/response.c287
-rw-r--r--apps/netutils/xmlrpc/xmlparser.c416
-rw-r--r--apps/nshlib/Kconfig494
-rw-r--r--apps/nshlib/Make.defs40
-rw-r--r--apps/nshlib/Makefile131
-rw-r--r--apps/nshlib/README.txt1170
-rw-r--r--apps/nshlib/nsh.h611
-rw-r--r--apps/nshlib/nsh_apps.c187
-rw-r--r--apps/nshlib/nsh_console.c432
-rw-r--r--apps/nshlib/nsh_console.h159
-rw-r--r--apps/nshlib/nsh_consolemain.c170
-rw-r--r--apps/nshlib/nsh_dbgcmds.c355
-rw-r--r--apps/nshlib/nsh_ddcmd.c643
-rw-r--r--apps/nshlib/nsh_envcmds.c338
-rw-r--r--apps/nshlib/nsh_fscmds.c1299
-rw-r--r--apps/nshlib/nsh_init.c102
-rw-r--r--apps/nshlib/nsh_mmcmds.c96
-rw-r--r--apps/nshlib/nsh_mntcmds.c434
-rw-r--r--apps/nshlib/nsh_netcmds.c864
-rw-r--r--apps/nshlib/nsh_netinit.c171
-rw-r--r--apps/nshlib/nsh_parse.c1550
-rw-r--r--apps/nshlib/nsh_proccmds.c310
-rw-r--r--apps/nshlib/nsh_romfsetc.c124
-rw-r--r--apps/nshlib/nsh_romfsimg.h89
-rw-r--r--apps/nshlib/nsh_telnetd.c187
-rw-r--r--apps/nshlib/nsh_test.c438
-rw-r--r--apps/nshlib/nsh_timcmds.c331
-rw-r--r--apps/nshlib/nsh_usbdev.c243
-rw-r--r--apps/nshlib/rcS.template5
-rw-r--r--apps/system/Kconfig20
-rw-r--r--apps/system/Make.defs51
-rw-r--r--apps/system/Makefile70
-rw-r--r--apps/system/free/Kconfig14
-rw-r--r--apps/system/free/Makefile114
-rw-r--r--apps/system/free/README.txt6
-rw-r--r--apps/system/free/free.c112
-rw-r--r--apps/system/i2c/Kconfig61
-rw-r--r--apps/system/i2c/Makefile102
-rw-r--r--apps/system/i2c/README.txt397
-rw-r--r--apps/system/i2c/i2c_bus.c99
-rw-r--r--apps/system/i2c/i2c_common.c216
-rw-r--r--apps/system/i2c/i2c_dev.c235
-rw-r--r--apps/system/i2c/i2c_get.c257
-rw-r--r--apps/system/i2c/i2c_main.c446
-rw-r--r--apps/system/i2c/i2c_set.c275
-rw-r--r--apps/system/i2c/i2c_verf.c249
-rw-r--r--apps/system/i2c/i2ctool.h210
-rw-r--r--apps/system/install/Kconfig14
-rw-r--r--apps/system/install/Makefile114
-rw-r--r--apps/system/install/README.txt26
-rw-r--r--apps/system/install/install.c412
-rw-r--r--apps/system/readline/Kconfig22
-rw-r--r--apps/system/readline/Makefile103
-rw-r--r--apps/system/readline/readline.c404
-rw-r--r--apps/vsn/Kconfig11
-rw-r--r--apps/vsn/Make.defs51
-rw-r--r--apps/vsn/Makefile71
-rw-r--r--apps/vsn/poweroff/Kconfig14
-rw-r--r--apps/vsn/poweroff/Makefile114
-rw-r--r--apps/vsn/poweroff/README.txt5
-rw-r--r--apps/vsn/poweroff/poweroff.c54
-rw-r--r--apps/vsn/ramtron/Kconfig14
-rw-r--r--apps/vsn/ramtron/Makefile114
-rw-r--r--apps/vsn/ramtron/README.txt7
-rw-r--r--apps/vsn/ramtron/ramtron.c99
-rw-r--r--apps/vsn/sdcard/Kconfig14
-rw-r--r--apps/vsn/sdcard/Makefile114
-rw-r--r--apps/vsn/sdcard/README.txt7
-rw-r--r--apps/vsn/sdcard/sdcard.c134
-rw-r--r--apps/vsn/sysinfo/Kconfig14
-rw-r--r--apps/vsn/sysinfo/Makefile114
-rw-r--r--apps/vsn/sysinfo/README.txt6
-rw-r--r--apps/vsn/sysinfo/sysinfo.c69
575 files changed, 111168 insertions, 0 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt
new file mode 100644
index 000000000..ced9250fa
--- /dev/null
+++ b/apps/ChangeLog.txt
@@ -0,0 +1,335 @@
+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-12-26 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.
+ * apps/examples/pwm: Add an NSH PWM command to drive and test a PWM
+ driver.
+ * apps/examples/can: Add an NSH CAN command to drive and test a CAN
+ driver in loopback mode.
+
+6.14 2012-01-15 Gregory Nutt <gnutt@nuttx.org>
+
+ * apps/examples/buttons/main.c: The test needs to call up_buttoninit() to
+ properly configure the button interrupt GPIOs.
+ * apps/examples/pwm: Add support to test the pulse count option recently
+ added to the PWM interface.
+
+6.15 2012-02-12 Gregory Nutt <gnutt@nuttx.org>
+
+ * apps/nshlib/nsh_serial.c and nsh_usbdev.c: If NuttX is configured to use
+ a USB serial console, then NSH needs to wait until the USB console is
+ connected and available.
+ * apps/examples/composite: Add a test of the USB composite device.
+ * apps/examples/Telnetd: Move the tiny uIP shell example from
+ netutils/Telnetd to examples/Telnetd. Enhanced the Telnetd daemon so that
+ it supports Telnetd via a TTY device driver: A new TTY device driver is
+ created when each new Telnet connection is created. The shell thread
+ is started with stdin, stdout, and stderr mapped to the TTY device.
+ * netutils/Telnetd: The old uIP Telnet demo is gone. In its place is a new
+ Telnet infrastructure. The new Telnet daemon creates sessions that are
+ "wrapped" as character devices and mapped to stdin, stdout, and stderr.
+ Now the Telnet session can be inherited by spawned tasks.
+ * examples/Telnetd: Add a test for the new Telnet daemon.
+ * examples/Telnetd/telnetd_driver.c: Move the internal socket structure from
+ the daemon's socket array into the driver's state data so that it will be
+ independent from the the Telnetd daemon.
+ * apps/system/readline: Moved the old nuttx/lib/stdio/lib_fgets.c here
+ and renamed it as readline(). The old fgets was simplied and the overloaded
+ readline functionality was removed.
+ * apps/netutils/ftpd: Add an FTPD server (does not even compile on initial
+ checkin).
+ * apps/examples/ftpd: Add a test for the FTPD server (untest on initial
+ check-in).
+ * apps/nshlib/nsh_fscmds.c: Add support for a 'dmesg' command that will
+ dump the system log if CONFIG_SYSLOG is selected.
+
+6.16 2012-03-10 Gregory Nutt <gnutt@nuttx.org>
+
+ * apps/examples/qencoder: Add a quadrature driver test.
+ * apps/examples/ostest/fpu.c: Add a test to verify that FPU registers
+ are properly saved and restored on context switches.
+ * apps/system/readline/readline.c: readline() will now treat either a
+ backspace or a DEL character as a backspace (i.e., deleting the character
+ to the left of the cursor). This makes NSH less dependent on particular
+ keyboard mappings of the Backspace key. Submitted by Mike Smith.
+ * apps/examples/cdcacm: An example that illustrates how the CDC/ACM driver
+ may to connected and disconnected through software control.
+ * apps/examples/nsh/nsh_main.c: If available, call up_cxxinitialize() to
+ initialize all statically defined C++ classes.
+ * apps/nshlib: Now supports a USB serial device for NSH console I/O. This
+ allows NSH to be used on boards that have USB but no serial connectors.
+
+6.17 2012-04-14 Gregory Nutt <gnutt@nuttx.org>
+
+ * apps/examples/can: Add conditional compilation so that the test can be
+ configured to only send messages or to only receive messages. This will
+ let the test work in other modes than simple loopback testing.
+ * apps/examples/hello and apps/examples/ostest: Can now be built as NSH
+ built-int functions.
+ * vsn/hello: Removed. The modified apps/examples/hello is enough "Hello,
+ World!"
+ * apps/examples/nxconsole: Add a test of the NX console device.
+ * apps/examples/nxconsole: The NX console example now supports running
+ the NuttShell (NSH) within an NX window.
+ * apps/system/readline: Now uses standard definitions from
+ include/nuttx/ascii.h and vt100.h
+ * Kconfig, */Kconfig: Added skeleton Kconfig files to all directories that
+ may need them.
+
+6.18 2012-05-19 Gregory Nutt <gnutt@nuttx.org>
+
+ * Kconfig: Continued Kconfig file updates (no longer tracking on a per-file
+ basis in the ChangeLog)
+ * apps/examples/watchdog: Add a watchdog timer example.
+ * apps/examples/tiff: Fix wrong path used for temporary file.
+ * apps/examples/touchscreen: Standardize the board-specific, touchscreen
+ initialization interfaces.
+
+6.19 2012-06-15 Gregory Nutt <gnutt@nuttx.org>
+
+ * apps/nshlib/nsh_usbdev.c: Add the capability to use an arbitrary USB
+ device as the console (not necessarily /dev/console). This is a useful
+ option because then you can still use the serial console to debug with.
+ * apps/nshlib/nsh_usbdev.c: User now has to press ENTER 3 times before
+ USB console will start. Otherwise, the USB console starts before there
+ is anyone at the other end to listen.
+ * apps/nshlib/nsh_usbdev.c and nsh_consolemain.c: Add support for the USB
+ capability when a USB console is used.
+ * apps/nshlib/nsh_fscmds.c: Add the 'mv' command
+
+6.20 2012-07-12 Gregory Nutt <gnutt@nuttx.org>
+
+ * namedapp/exec_namedapp.c - Correct an error when round robin scheduling
+ is enabled. The priority of the new, named application was erroneously
+ being set to the priority of the parent thread; losing its configured
+ priority. Reported by Mike Smith.
+
+6.21 2012-08-25 Gregory Nutt <gnutt@nuttx.org>
+
+ * apps/include/: Stylistic clean-up of all header files.
+ * apps/modbus and apps/include/modbus: A port of freemodbus-v1.5.0
+ has been added to the NuttX apps/ source tree.
+ * apps/examples/modbus: A port of the freemodbus-v1.5.0 "demo"
+ program that will be used to verify the FreeModBus port
+ * apps/modbus: Don't use strerror(). It is just too big.
+ * apps/modbus: Add CONFIG_MB_TERMIOS. If the driver doesn't support
+ termios ioctls, then don't bother trying to configure the baud, parity
+ etc.
+ * apps/nshlib: If waitpid() is supported, then NSH now catches the
+ return value from spawned applications (provided by Mike Smith)
+ * apps/nshlib: Lock the scheduler while starting built-in applications
+ in order to eliminate race conditions (also from Mike Smith).
+ * apps/examples/adc, pwm, and qencoder: Add support for testing
+ devices with multiple ADC, PWM, and QE devices.
+ * apps/nshlib/nsh_mntcmds.c: Separated mount-related commands out of
+ nsh_fscmds.c. Extended to the mount command so that if no arguments
+ are provided, then the current mountpoints are enumerated.
+ * apps/nshlib/nsh_mntcmds.c: Add an NSH df command to list the
+ properties of mounted file systems.
+ * apps/nshlib/nsh_parse.c: Extend help command options. 'help' with
+ no arguments outputs a short list of commands. With -v lists all
+ command line details. A command name can be added to just get
+ help on one command.
+ * system/readline.c: If character input/output is interrupted by a
+ signal, then readline() will try the read/write again.
+ * apps/*/Make.defs: Numerous fixes needed to use the automated
+ configuration (from Richard Cochran).
+
+6.22 2012-xx-xx Gregory Nutt <gnutt@nuttx.org>
+
+ * apps/netutils/thttpd/thttpd_cgi.c: Missing NULL in argv[]
+ list (contributed by Kate).
+ * apps/nshlib/nsh_parse.c: CONFIG_NSH_DISABLE_WGET not CONFIG_NSH_DISABLE_GET
+ in one location (found by Kate).
+ * apps/examples/ostest/prioinherit.c: Limit the number of test
+ threds to no more than 3 of each priority. Bad things happen
+ when the existing logic tried to created several hundred test
+ treads!
+ * apps/nshlib/nsh.h: Both CONFIG_LIBC_STRERROR and CONFIG_NSH_STRERROR
+ must be defined to use strerror() with NSH.
+ * apps/examples/*/*_main.c, system/i2c/i2c_main.c, and others: Added
+ configuration variable CONFIG_USER_ENTRYPOINT that may be used to change
+ the default entry from user_start to some other symbol. Contributed by
+ Kate.
+ * apps/netutils/webserver/httpd/c: Fix a typo that as introduced in
+ version r4402: 'lese' instead of 'else' (Noted by Max Holtzberg).
+ * tools/mkfsdata.pl: The uIP web server CGI image making perl script was
+ moved from apps/netutils/webserver/makefsdata to nuttx/tools/mkfsdata.pl
+ (Part of a larger change submitted by Max Holtzberg).
+ * apps/netutils/webserver, apps/examples/uip, and apps/include/netutils/httpd.h:
+ The "canned" version of the uIP web servers content that was at
+ netutils/webserver/httpd_fsdata.c has been replaced with a dynamically
+ built configuration located at apps/examples/uip (Contributed by
+ Max Holtzberg).
+ * apps/netutils/webserver: Several inenhancements from Kate including the
+ ability to elide scripting and SERVER headers and the ability to map
+ files into memory before transferring them.
+ * apps/netutils/webserver: Add ability to map a URL to CGI function.
+ Contributed by Kate.
+ * apps/nshlib/nsh_mntcmds.c: The changes of 6.21 introduced holes in the
+ error handling: Now the number of arguments to mount can be 0 or 4.
+ Additional parameter checking is required to prevent mysterious errors
+ (submiteed by Kate).
+ * apps/netutils/webserver/httpd_mmap.c: Fix errors when the mmap()
+ length is zero (submitted by Kate).
+ * apps/netutils/webserver/httpd_sendfile.c: Add and option,
+ CONFIG_NETUTILS_HTTPD_SENDFILE to transfer files using the NuttX
+ sendfile() interface.
+ * apps/netutils/discover: A UDP network discovery utility contributed
+ by Max Holtzberg.
+ * apps/examples/discover: A test example for the UDP network discovery
+ utility (also contribed by Max Holtzberg).
+ * apps/examples/*/main.c: Too many files called main.c. Each renamed
+ to something unique so that they will not collide in the archive.
+ * apps/netutils/xmlrpc: The Embeddable Lightweight XML-RPC Server
+ discussed at http://www.drdobbs.com/web-development/\
+ an-embeddable-lightweight-xml-rpc-server/184405364. Contributed by
+ Max Holtzberg.
+ * apps/netutils/uip_listenon.c: Logic in uip_server.c that creates
+ the listening socket was moved to this new file to support re-use.
+ Contributed by Kate.
+
diff --git a/apps/Kconfig b/apps/Kconfig
new file mode 100644
index 000000000..1f38c58ba
--- /dev/null
+++ b/apps/Kconfig
@@ -0,0 +1,36 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+menu "Named Applications"
+source "$APPSDIR/namedapp/Kconfig"
+endmenu
+
+menu "Examples"
+source "$APPSDIR/examples/Kconfig"
+endmenu
+
+menu "Interpreters"
+source "$APPSDIR/interpreters/Kconfig"
+endmenu
+
+menu "Network Utilities"
+source "$APPSDIR/netutils/Kconfig"
+endmenu
+
+menu "ModBus"
+source "$APPSDIR/modbus/Kconfig"
+endmenu
+
+menu "NSH Library"
+source "$APPSDIR/nshlib/Kconfig"
+endmenu
+
+menu "System NSH Add-Ons"
+source "$APPSDIR/system/Kconfig"
+endmenu
+
+menu "VSN board Add-Ons"
+source "$APPSDIR/vsn/Kconfig"
+endmenu
diff --git a/apps/Make.defs b/apps/Make.defs
new file mode 100644
index 000000000..53ac7f8be
--- /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 <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.
+#
+############################################################################
+
+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..3a59fd6b4
--- /dev/null
+++ b/apps/Makefile
@@ -0,0 +1,173 @@
+############################################################################
+# apps/Makefile
+#
+# Copyright (C) 2011-2012 Uros Platise. All rights reserved.
+# Authors: Uros Platise <uros.platise@isotel.eu>
+# 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)/Make.defs
+-include $(TOPDIR)/.config
+
+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 modbus namedapp nshlib netutils system vsn
+
+# There are two different mechanisms for obtaining the list of configured
+# directories:
+#
+# (1) In the legacy method, these paths are all provided in the appconfig
+# file that is copied to the top-level apps/ directory as .config
+# (2) With the development of the NuttX configuration tool, however, the
+# selected applications are now enabled by the configuration tool.
+# The apps/.config file is no longer used. Instead, the set of
+# configured build directories can be found by including a Make.defs
+# file contained in each of the apps/subdirectories.
+#
+# When the NuttX configuration tools executes, it will always define the
+# configure CONFIG_NUTTX_NEWCONFIG to select between these two cases. Then
+# legacy appconfig files will still work but newly configuration files will
+# also work. Eventually the CONFIG_NUTTX_NEWCONFIG option will be phased
+# out.
+
+ifeq ($(CONFIG_NUTTX_NEWCONFIG),y)
+
+include examples/Make.defs
+include graphics/Make.defs
+include interpreters/Make.defs
+include modbus/Make.defs
+include namedapp/Make.defs
+include netutils/Make.defs
+include nshlib/Make.defs
+include system/Make.defs
+include vsn/Make.defs
+
+# 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 =
+
+# The legacy case:
+
+else
+-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
+endif
+
+# 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..f9c9ececd
--- /dev/null
+++ b/apps/README.txt
@@ -0,0 +1,211 @@
+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
+ Building NuttX with Board-Specific Pieces Outside the Source Tree
+
+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, application 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 += examples/hello vsn/poweroff
+
+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 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 examples/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
+
+Building NuttX with Board-Specific Pieces Outside the Source Tree
+-----------------------------------------------------------------
+
+Q: Has anyone come up with a tidy way to build NuttX with board-
+ specific pieces outside the source tree?
+A: Here are four:
+
+ 1) There is a make target called 'make export'. It will build
+ NuttX, then bundle all of the header files, libaries, startup
+ objects, and other build components into a .zip file. You
+ can can move that .zip file into any build environment you
+ want. You even build NuttX under a DOS CMD window.
+
+ This make target is documented in the top level nuttx/README.txt.
+
+ 2) You can replace the entire apps/ directory. If there is
+ nothing in the apps/ directory that you need, you can define
+ CONFIG_APPS_DIR in your .config file so that it points to a
+ different, custom application directory.
+
+ You can copy any pieces that you like from the old apps/directory
+ to your custom apps directory as necessary.
+
+ This is documented in NuttX/configs/README.txt and
+ nuttx/Documentation/NuttxPortingGuide.html (Online at
+ http://nuttx.sourceforge.net/NuttxPortingGuide.html#apndxconfigs
+ under Build options). And in the apps/README.txt file.
+
+ 3) If you like the random collection of stuff in the apps/ directory
+ but just want to expand the existing components with your own,
+ external sub-directory then there is an easy way to that too:
+ You just create the sympolic link at apps/external that
+ redirects to your application sub-directory. The apps/Makefile
+ will always automatically check for the existence of an
+ apps/external directory and if it exists, it will automatically
+ incorporate it into the build.
+
+ This feature of the apps/Makefile is documented only here.
+
+ You can, for example, create a script called install.sh that
+ installs a custom application, configuration, and board specific
+ directory:
+
+ a) Copy 'MyBoard' directory to configs/MyBoard.
+ b) Add a symbolic link to MyApplication at apps/external
+ c) Configure NuttX (usually by:
+
+ tools/configure.sh MyBoard/MyConfiguration
+
+ or simply by copying defconfig->nutt/.config,
+ setenv.sh->nuttx/setenv.sh, Make.defs->nuttx/Make.defs,
+ appconfig->apps/.config
+
+ Using the 'external' link makes it especially easy to add a
+ 'built-in' application an existing configuration.
+
+ 4) Add any link to apps/
+
+ a) Add symbolic links apps/ to as many other directories as you
+ want.
+ b) Then just add the (relative) paths to the links in your
+ appconfig file (that becomes the apps/.config file).
+
+ That is basically the same as my option #3 but doesn't use the
+ magic 'external' link. The toplevel apps/Makefile will always
+ to build whatever in finds in the apps/.config file (plus the
+ external link if present).
diff --git a/apps/examples/Kconfig b/apps/examples/Kconfig
new file mode 100644
index 000000000..865268add
--- /dev/null
+++ b/apps/examples/Kconfig
@@ -0,0 +1,208 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+menu "ADC Example"
+source "$APPSDIR/examples/adc/Kconfig"
+endmenu
+
+menu "Buttons Example"
+source "$APPSDIR/examples/buttons/Kconfig"
+endmenu
+
+menu "CAN Example"
+source "$APPSDIR/examples/can/Kconfig"
+endmenu
+
+menu "USB CDC/ACM Class Driver Example"
+source "$APPSDIR/examples/cdcacm/Kconfig"
+endmenu
+
+menu "USB composite Class Driver Example"
+source "$APPSDIR/examples/composite/Kconfig"
+endmenu
+
+menu "DHCP Server Example"
+source "$APPSDIR/examples/dhcpd/Kconfig"
+endmenu
+
+menu "FTP Client Example"
+source "$APPSDIR/examples/ftpc/Kconfig"
+endmenu
+
+menu "FTP Server Example"
+source "$APPSDIR/examples/ftpd/Kconfig"
+endmenu
+
+menu "\"Hello, World!\" Example"
+source "$APPSDIR/examples/hello/Kconfig"
+endmenu
+
+menu "\"Hello, World!\" C++ Example"
+source "$APPSDIR/examples/helloxx/Kconfig"
+endmenu
+
+menu "USB HID Keyboard Example"
+source "$APPSDIR/examples/hidkbd/Kconfig"
+endmenu
+
+menu "IGMP Example"
+source "$APPSDIR/examples/igmp/Kconfig"
+endmenu
+
+menu "LCD Read/Write Example"
+source "$APPSDIR/examples/lcdrw/Kconfig"
+endmenu
+
+menu "Memory Management Example"
+source "$APPSDIR/examples/mm/Kconfig"
+endmenu
+
+menu "File System Mount Example"
+source "$APPSDIR/examples/mount/Kconfig"
+endmenu
+
+menu "FreeModBus Example"
+source "$APPSDIR/examples/modbus/Kconfig"
+endmenu
+
+menu "Network Test Example"
+source "$APPSDIR/examples/nettest/Kconfig"
+endmenu
+
+menu "NuttShell (NSH) Example"
+source "$APPSDIR/examples/nsh/Kconfig"
+endmenu
+
+menu "NULL Example"
+source "$APPSDIR/examples/null/Kconfig"
+endmenu
+
+menu "NX Graphics Example"
+source "$APPSDIR/examples/nx/Kconfig"
+endmenu
+
+menu "NxConsole Example"
+source "$APPSDIR/examples/nxconsole/Kconfig"
+endmenu
+
+menu "NXFFS File System Example"
+source "$APPSDIR/examples/nxffs/Kconfig"
+endmenu
+
+menu "NXFLAT Example"
+source "$APPSDIR/examples/nxflat/Kconfig"
+endmenu
+
+menu "NX Graphics \"Hello, World!\" Example"
+source "$APPSDIR/examples/nxhello/Kconfig"
+endmenu
+
+menu "NX Graphics image Example"
+source "$APPSDIR/examples/nximage/Kconfig"
+endmenu
+
+menu "NX Graphics lines Example"
+source "$APPSDIR/examples/nxlines/Kconfig"
+endmenu
+
+menu "NX Graphics Text Example"
+source "$APPSDIR/examples/nxtext/Kconfig"
+endmenu
+
+menu "OS Test Example"
+source "$APPSDIR/examples/ostest/Kconfig"
+endmenu
+
+menu "Pascal \"Hello, World!\"example"
+source "$APPSDIR/examples/pashello/Kconfig"
+endmenu
+
+menu "Pipe Example"
+source "$APPSDIR/examples/pipe/Kconfig"
+endmenu
+
+menu "Poll Example"
+source "$APPSDIR/examples/poll/Kconfig"
+endmenu
+
+menu "Pulse Width Modulation (PWM) Example"
+source "$APPSDIR/examples/pwm/Kconfig"
+endmenu
+
+menu "Quadrature Encoder Example"
+source "$APPSDIR/examples/qencoder/Kconfig"
+endmenu
+
+menu "RGMP Example"
+source "$APPSDIR/examples/rgmp/Kconfig"
+endmenu
+
+menu "ROMFS Example"
+source "$APPSDIR/examples/romfs/Kconfig"
+endmenu
+
+menu "sendmail Example"
+source "$APPSDIR/examples/sendmail/Kconfig"
+endmenu
+
+menu "Serial Loopback Example"
+source "$APPSDIR/examples/serloop/Kconfig"
+endmenu
+
+menu "Telnet Daemon Example"
+source "$APPSDIR/examples/telnetd/Kconfig"
+endmenu
+
+menu "THTTPD Web Server Example"
+source "$APPSDIR/examples/thttpd/Kconfig"
+endmenu
+
+menu "TIFF Generation Example"
+source "$APPSDIR/examples/tiff/Kconfig"
+endmenu
+
+menu "Touchscreen Example"
+source "$APPSDIR/examples/touchscreen/Kconfig"
+endmenu
+
+menu "UDP Example"
+source "$APPSDIR/examples/udp/Kconfig"
+endmenu
+
+menu "UDP Discovery Daemon Example"
+source "$APPSDIR/examples/discover/Kconfig"
+endmenu
+
+menu "uIP Web Server Example"
+source "$APPSDIR/examples/uip/Kconfig"
+endmenu
+
+menu "USB Serial Test Example"
+source "$APPSDIR/examples/usbserial/Kconfig"
+endmenu
+
+menu "USB Mass Storage Class Example"
+source "$APPSDIR/examples/usbstorage/Kconfig"
+endmenu
+
+menu "USB Serial Terminal Example"
+source "$APPSDIR/examples/usbterm/Kconfig"
+endmenu
+
+menu "Watchdog timer Example"
+source "$APPSDIR/examples/watchdog/Kconfig"
+endmenu
+
+menu "wget Example"
+source "$APPSDIR/examples/wget/Kconfig"
+endmenu
+
+menu "WLAN Example"
+source "$APPSDIR/examples/wlan/Kconfig"
+endmenu
+
+menu "XML RPC Example"
+source "$APPSDIR/examples/xmlrpc/Kconfig"
+endmenu
diff --git a/apps/examples/Make.defs b/apps/examples/Make.defs
new file mode 100644
index 000000000..a6e0ae88e
--- /dev/null
+++ b/apps/examples/Make.defs
@@ -0,0 +1,231 @@
+############################################################################
+# apps/examples/Make.defs
+# Adds selected applications to apps/ build
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_EXAMPLES_ADC),y)
+CONFIGURED_APPS += examples/adc
+endif
+
+ifeq ($(CONFIG_EXAMPLES_BUTTONS),y)
+CONFIGURED_APPS += examples/buttons
+endif
+
+ifeq ($(CONFIG_EXAMPLES_CAN),y)
+CONFIGURED_APPS += examples/can
+endif
+
+ifeq ($(CONFIG_EXAMPLES_CDCACM),y)
+CONFIGURED_APPS += examples/cdcacm
+endif
+
+ifeq ($(CONFIG_EXAMPLES_COMPOSITE),y)
+CONFIGURED_APPS += examples/composite
+endif
+
+ifeq ($(CONFIG_EXAMPLES_DHCPD),y)
+CONFIGURED_APPS += examples/dhcpd
+endif
+
+ifeq ($(CONFIG_EXAMPLE_DISCOVER),y)
+CONFIGURED_APPS += examples/discover
+endif
+
+ifeq ($(CONFIG_EXAMPLES_FTPC),y)
+CONFIGURED_APPS += examples/ftpc
+endif
+
+ifeq ($(CONFIG_EXAMPLES_FTPD),y)
+CONFIGURED_APPS += examples/ftpd
+endif
+
+ifeq ($(CONFIG_EXAMPLES_HELLO),y)
+CONFIGURED_APPS += examples/hello
+endif
+
+ifeq ($(CONFIG_EXAMPLES_HELLOXX),y)
+CONFIGURED_APPS += examples/helloxx
+endif
+
+ifeq ($(CONFIG_EXAMPLES_HIDKBD),y)
+CONFIGURED_APPS += examples/hidkbd
+endif
+
+ifeq ($(CONFIG_EXAMPLES_IGMP),y)
+CONFIGURED_APPS += examples/igmp
+endif
+
+ifeq ($(CONFIG_EXAMPLES_LCDRW),y)
+CONFIGURED_APPS += examples/lcdrw
+endif
+
+ifeq ($(CONFIG_EXAMPLES_MM),y)
+CONFIGURED_APPS += examples/mm
+endif
+
+ifeq ($(CONFIG_EXAMPLES_MOUNT),y)
+CONFIGURED_APPS += examples/mount
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NETTEST),y)
+CONFIGURED_APPS += examples/nettest
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NSH),y)
+CONFIGURED_APPS += examples/nsh
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NULL),y)
+CONFIGURED_APPS += examples/null
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NX),y)
+CONFIGURED_APPS += examples/nx
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NXCONSOLE),y)
+CONFIGURED_APPS += examples/nxconsole
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NXFFS),y)
+CONFIGURED_APPS += examples/nxffs
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NXFLAT),y)
+CONFIGURED_APPS += examples/nxflat
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NXHELLO),y)
+CONFIGURED_APPS += examples/nxhello
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NXIMAGE),y)
+CONFIGURED_APPS += examples/nximage
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NXLINES),y)
+CONFIGURED_APPS += examples/nxlines
+endif
+
+ifeq ($(CONFIG_EXAMPLES_NXTEXT),y)
+CONFIGURED_APPS += examples/nxtext
+endif
+
+ifeq ($(CONFIG_EXAMPLES_OSTEST),y)
+CONFIGURED_APPS += examples/ostest
+endif
+
+ifeq ($(CONFIG_EXAMPLES_PASHELLO),y)
+CONFIGURED_APPS += examples/pashello
+endif
+
+ifeq ($(CONFIG_EXAMPLES_PIPE),y)
+CONFIGURED_APPS += examples/pipe
+endif
+
+ifeq ($(CONFIG_EXAMPLES_POLL),y)
+CONFIGURED_APPS += examples/poll
+endif
+
+ifeq ($(CONFIG_EXAMPLES_PWM),y)
+CONFIGURED_APPS += examples/pwm
+endif
+
+ifeq ($(CONFIG_EXAMPLES_QENCODER),y)
+CONFIGURED_APPS += examples/qencoder
+endif
+
+ifeq ($(CONFIG_EXAMPLES_RGMP),y)
+CONFIGURED_APPS += examples/rgmp
+endif
+
+ifeq ($(CONFIG_EXAMPLES_ROMFS),y)
+CONFIGURED_APPS += examples/romfs
+endif
+
+ifeq ($(CONFIG_EXAMPLES_SENDMAIL),y)
+CONFIGURED_APPS += examples/sendmail
+endif
+
+ifeq ($(CONFIG_EXAMPLES_SERLOOP),y)
+CONFIGURED_APPS += examples/serloop
+endif
+
+ifeq ($(CONFIG_EXAMPLES_TELNETD),y)
+CONFIGURED_APPS += examples/telnetd
+endif
+
+ifeq ($(CONFIG_EXAMPLES_THTTPD),y)
+CONFIGURED_APPS += examples/thttpd
+endif
+
+ifeq ($(CONFIG_EXAMPLES_TIFF),y)
+CONFIGURED_APPS += examples/tiff
+endif
+
+ifeq ($(CONFIG_EXAMPLES_TOUCHSCREEN),y)
+CONFIGURED_APPS += examples/touchscreen
+endif
+
+ifeq ($(CONFIG_EXAMPLES_UDP),y)
+CONFIGURED_APPS += examples/udp
+endif
+
+ifeq ($(CONFIG_EXAMPLES_UIP),y)
+CONFIGURED_APPS += examples/uip
+endif
+
+ifeq ($(CONFIG_EXAMPLES_USBSERIAL),y)
+CONFIGURED_APPS += examples/usbserial
+endif
+
+ifeq ($(CONFIG_EXAMPLES_USBMSC),y)
+CONFIGURED_APPS += examples/usbmsc
+endif
+
+ifeq ($(CONFIG_EXAMPLES_USBTERM),y)
+CONFIGURED_APPS += examples/usbterm
+endif
+
+ifeq ($(CONFIG_EXAMPLES_WGET),y)
+CONFIGURED_APPS += examples/wget
+endif
+
+ifeq ($(CONFIG_EXAMPLES_WLAN),y)
+CONFIGURED_APPS += examples/wlan
+endif
+
+ifeq ($(CONFIG_EXAMPLES_XMLRPC),y)
+CONFIGURED_APPS += examples/xmlrpc
+endif
diff --git a/apps/examples/Makefile b/apps/examples/Makefile
new file mode 100644
index 000000000..453f99ce7
--- /dev/null
+++ b/apps/examples/Makefile
@@ -0,0 +1,131 @@
+############################################################################
+# apps/examples/Makefile
+#
+# Copyright (C) 2011-2012 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 can cdcacm composite dhcpd discover ftpc ftpd hello
+SUBDIRS += helloxx hidkbd igmp lcdrw mm modbus mount nettest nsh null nx
+SUBDIRS += nxconsole nxffs nxflat nxhello nximage nxlines nxtext ostest
+SUBDIRS += pashello pipe poll pwm qencoder rgmp romfs serloop telnetd
+SUBDIRS += thttpd tiff touchscreen udp uip usbserial sendmail usbstorage
+SUBDIRS += usbterm watchdog wget wlan
+
+# Sub-directories that might need context setup. Directories may need
+# context setup for a variety of reasons, but the most common is because
+# the example may be built as an NSH built-in function.
+#
+# Directories that may be built as NSH built-in functions may have their
+# own configuration setting (like CONFIG_EXAMPLES_HELLOXX_BUILTIN), but
+# many only depend on the generic CONFIG_NSH_BUILTIN_APPS setting. And
+# there a few which an ONLY be built as NSH built-in applications; these
+# are included in the list unconditionally.
+
+CNTXTDIRS = pwm
+
+ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
+CNTXTDIRS += adc can cdcacm composite discover ftpd dhcpd modbus nettest
+CNTXTDIRS += qencoder telnetd watchdog
+endif
+
+ifeq ($(CONFIG_EXAMPLES_HELLO_BUILTIN),y)
+CNTXTDIRS += hello
+endif
+ifeq ($(CONFIG_EXAMPLES_HELLOXX_BUILTIN),y)
+CNTXTDIRS += helloxx
+endif
+ifeq ($(CONFIG_EXAMPLES_LCDRW_BUILTIN),y)
+CNTXTDIRS += lcdrw
+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_OSTEST_BUILTIN),y)
+CNTXTDIRS += ostest
+endif
+ifeq ($(CONFIG_EXAMPLES_TIFF_BUILTIN),y)
+CNTXTDIRS += tiff
+endif
+ifeq ($(CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN),y)
+CNTXTDIRS += touchscreen
+endif
+ifeq ($(CONFIG_EXAMPLES_USBMSC_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..12d6d3892
--- /dev/null
+++ b/apps/examples/README.txt
@@ -0,0 +1,1694 @@
+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.
+
+ This test depends on these specific ADC/NSH configurations settings (your
+ specific ADC settings might require additional settings).
+
+ CONFIG_ADC - Enabled ADC support
+ CONFIG_NSH_BUILTIN_APPS - Build the ADC test as an NSH built-in function.
+ Default: Built as a standalone problem
+
+ Specific configuration options for this example include:
+
+ CONFIG_EXAMPLES_ADC_DEVPATH - The default 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/can
+^^^^^^^^^^^^
+
+ If the CAN device is configured in loopback mode, then this example can
+ be used to test the CAN device in loop back mode. It simple sinces a
+ sequence of CAN messages and verifies that those messages are returned
+ exactly as sent.
+
+ This test depends on these specific CAN/NSH configurations settings (your
+ specific CAN settings might require additional settings).
+
+ CONFIG_CAN - Enables CAN support.
+ CONFIG_CAN_LOOPBACK - A CAN driver may or may not support a loopback
+ mode for testing. The STM32 CAN driver does support loopback mode.
+ CONFIG_NSH_BUILTIN_APPS - Build the CAN test as an NSH built-in function.
+ Default: Built as a standalone problem
+
+ Specific configuration options for this example include:
+
+ CONFIG_EXAMPLES_CAN_DEVPATH - The path to the CAN device. Default: /dev/can0
+ CONFIG_EXAMPLES_CAN_NMSGS - If CONFIG_NSH_BUILTIN_APPS
+ is defined, then the number of loops is provided on the command line
+ and this value is ignored. Otherwise, this number of CAN message is
+ collected and the program terminates. Default: If built as an NSH
+ built-in, the default is 32. Otherwise messages are sent and received
+ indefinitely.
+
+ The default behavior assumes loopback mode. Messages are sent, then read
+ and verified. The behavior can be altered for other kinds of testing where
+ the test only sends or received (but does not verify) can messages.
+
+ CONFIG_EXAMPLES_CAN_READONLY - Only receive messages
+ CONFIG_EXAMPLES_CAN_WRITEONLY - Only send messages
+
+examples/cdcacm
+^^^^^^^^^^^^^^^
+
+ This very simple example shows how a USB CDC/ACM serial can be dynamically
+ connected and disconnected from a host. This example can only be used as
+ an NSH built-int command. If built-in, then two new NSH commands will be
+ supported:
+
+ 1. sercon - Connect the CDC/ACM serial device
+ 2. serdis - Disconnect the CDC/ACM serial device
+
+ Configuration prequisites (not complete):
+
+ CONFIG_USBDEV=y : USB device support must be enabled
+ CONFIG_CDCACM=y : The CDC/ACM driver must be built
+ CONFIG_NSH_BUILTIN_APPS : NSH built-in application support must be enabled
+
+ Configuration options specific to this example:
+
+ CONFIG_EXAMPLES_CDCACM_DEVMINOR : The minor number of the CDC/ACM device.
+ : i.e., the 'x' in /dev/ttyACMx
+
+ If CONFIG_USBDEV_TRACE is enabled (or CONFIG_DEBUG and CONFIG_DEBUG_USB, or
+ CONFIG_USBDEV_TRACE), then the example code will also initialize the USB trace
+ output. The amount of trace output can be controlled using:
+
+ CONFIG_EXAMPLES_CDCACM_TRACEINIT
+ Show initialization events
+ CONFIG_EXAMPLES_CDCACM_TRACECLASS
+ Show class driver events
+ CONFIG_EXAMPLES_CDCACM_TRACETRANSFERS
+ Show data transfer events
+ CONFIG_EXAMPLES_CDCACM_TRACECONTROLLER
+ Show controller events
+ CONFIG_EXAMPLES_CDCACM_TRACEINTERRUPTS
+ Show interrupt-related events.
+
+ Note: This example is only enables or disable USB CDC/ACM via the NSH
+ 'sercon' and 'serdis' command. It will enable and disable tracing per
+ the settings before enabling and after disabling the CDC/ACM device. It
+ will not, however, monitor buffered trace data in the interim. If
+ CONFIG_USBDEV_TRACE is defined (and the debug options are not), other
+ application logic will need to monitor the buffered trace data.
+
+examples/composite
+^^^^^^^^^^^^^^^^^^
+
+ This example test a USB composite device. The only supported composite is
+ CDC/ACM serial with a USB mass storage device.
+
+ Required overall configuration:
+
+ CONFIG_USBDEV=y - USB device support
+ CONFIG_USBDEV_COMPOSITE=y - USB composite device support
+ CONFIG_COMPOSITE_IAD=y - Interface associate descriptor needed
+
+ CONFIG_CDCACM=y - USB CDC/ACM serial device support
+ CONFIG_CDCACM_COMPOSITE=y - USB CDC/ACM serial composite device support
+ CONFIG_CDCACM_IFNOBASE=0 - CDC/ACM interfaces start with number 0
+ CONFIG_CDCACM_STRBASE=4 - Base of string numbers (not really needed)
+ CONFIG_CDCACM_EPINTIN=1 - Endpoint numbers must be unique
+ CONFIG_CDCACM_EPBULKIN=2
+ CONFIG_CDCACM_EPBULKOUT=3
+
+ CONFIG_USBMSC - USB mass storage device support
+ CONFIG_USBMSC_COMPOSITE=y - USB mass storage composite device support
+ CONFIG_USBMSC_IFNOBASE=2 - USB mass storage interfaces start with number 2
+ CONFIG_USBMSC_STRBASE=4 - Base of string numbers (needed)
+ CONFIG_USBMSC_EPBULKOUT=4 - Endpoint numbers must be unique
+ CONFIG_USBMSC_EPBULKIN=5
+
+ CONFIG_NSH_BUILTIN_APPS
+ This example can be built as two NSH "built-in" commands if this option
+ is selected: 'conn' will connect the USB composite device; 'msdis'
+ will disconnect the USB composite device.
+
+ Configuration options unique to this example:
+
+ CONFIG_EXAMPLES_COMPOSITE_DEBUGMM
+ Enables some debug tests to check for memory usage and memory leaks.
+
+ CONFIG_EXAMPLES_COMPOSITE_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_COMPOSITE_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_COMPOSITE_DEVPATH1
+ The full path to the registered block driver. Default is "/dev/mmcsd0"
+ CONFIG_EXAMPLES_COMPOSITE_DEVMINOR2 and CONFIG_EXAMPLES_COMPOSITE_DEVPATH2
+ Similar parameters that would have to be provided if CONFIG_EXAMPLES_COMPOSITE_NLUNS
+ is 2 or 3. No defaults.
+ CONFIG_EXAMPLES_COMPOSITE_DEVMINOR3 and CONFIG_EXAMPLES_COMPOSITE_DEVPATH2
+ Similar parameters that would have to be provided if CONFIG_EXAMPLES_COMPOSITE_NLUNS
+ is 3. No defaults.
+ CONFIG_EXAMPLES_COMPOSITE_BUFLEN. Default 256.
+
+ CONFIG_EXAMPLES_COMPOSITE_TTYUSB - The minor number of the USB serial device.
+ Default is zero (corresponding to /dev/ttyUSB0 or /dev/ttyACM0). Default is zero.
+ CCONFIG_EXAMPLES_COMPOSITE_SERDEV - The string corresponding to
+ CONFIG_EXAMPLES_COMPOSITE_TTYUSB. The default is "/dev/ttyUSB0" (for the PL2303
+ emulation) or "/dev/ttyACM0" (for the CDC/ACM serial device).
+ CONFIG_EXAMPLES_COMPOSITE_BUFSIZE - The size of the serial I/O buffer in
+ bytes. Default 256 bytes.
+
+ 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_COMPOSITE_TRACEINIT
+ Show initialization events
+ CONFIG_EXAMPLES_COMPOSITE_TRACECLASS
+ Show class driver events
+ CONFIG_EXAMPLES_COMPOSITE_TRACETRANSFERS
+ Show data transfer events
+ CONFIG_EXAMPLES_COMPOSITE_TRACECONTROLLER
+ Show controller events
+ CONFIG_EXAMPLES_COMPOSITE_TRACEINTERRUPTS
+ Show interrupt-related events.
+
+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/discover
+^^^^^^^^^^^^^^^^^
+
+ This example exercises netutils/discover utility. This example initializes
+ and starts the UDP discover daemon. This daemon is useful for discovering
+ devices in local networks, especially with DHCP configured devices. It
+ listens for UDP broadcasts which also can include a device class so that
+ groups of devices can be discovered. It is also possible to address all
+ classes with a kind of broadcast discover.
+
+ This example will automatically be built as an NSH built-in if
+ CONFIG_NSH_BUILTIN_APPS is selected. Otherwise, it will be a standalone
+ program with entry point "discover_main".
+
+ NuttX configuration settings:
+
+ CONFIG_EXAMPLE_DISCOVER_DHCPC - DHCP Client
+ CONFIG_EXAMPLE_DISCOVER_NOMAC - Use canned MAC address
+ CONFIG_EXAMPLE_DISCOVER_IPADDR - Target IP address
+ CONFIG_EXAMPLE_DISCOVER_DRIPADDR - Router IP address
+ CONFIG_EXAMPLE_DISCOVER_NETMASK - Network Mask
+
+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: By default, FTPC uses readline to get data from stdin. So your
+ appconfig file must have the following build path:
+
+ CONFIGURED_APPS += system/readline
+
+ NOTE: If you use the ftpc task over a telnet NSH connection, then you
+ should set the following configuration item:
+
+ CONFIG_EXAMPLES_FTPC_FGETS=y
+
+ By default, the FTPC client will use readline() to get characters from
+ the console. Readline includes and command-line editor and echos
+ characters received in stdin back through stdout. Neither of these
+ behaviors are desire-able if Telnet is used.
+
+ 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/ftpd
+^^^^^^^^^^^^^^
+
+ This example exercises the FTPD daemon at apps/netuils/ftpd. Below are
+ configurations specific to the FTPD example (the FTPD daemon itself may
+ require other configuration options as well).
+
+ CONFIG_EXAMPLES_FTPD_PRIO - Priority of the FTP daemon.
+ Default: SCHED_PRIORITY_DEFAULT
+ CONFIG_EXAMPLES_FTPD_STACKSIZE - Stack size allocated for the
+ FTP daemon. Default: 2048
+ CONFIG_EXAMPLES_FTPD_NONETINIT - Define to suppress configuration of the
+ network by apps/examples/ftpd. You would need to suppress network
+ configuration if the network is configuration prior to running the
+ example.
+
+ NSH always initializes the network so if CONFIG_NSH_BUILTIN_APPS is
+ defined, so is CONFIG_EXAMPLES_FTPD_NONETINIT (se it does not explicitly
+ need to be defined in that case):
+
+ CONFIG_NSH_BUILTIN_APPS - Build the FTPD daemon example test as an
+ NSH built-in function. By default the FTPD daemon will be built
+ as a standalone application.
+
+ If CONFIG_EXAMPLES_FTPD_NONETINIT is not defined, then the following may
+ be specified to customized the network configuration:
+
+ CONFIG_EXAMPLE_FTPD_NOMAC - If the hardware has no MAC address of its
+ own, define this =y to provide a bogus address for testing.
+ CONFIG_EXAMPLE_FTPD_IPADDR - The target IP address. Default 10.0.0.2
+ CONFIG_EXAMPLE_FTPD_DRIPADDR - The default router address. Default
+ 10.0.0.1
+ CONFIG_EXAMPLE_FTPD_NETMASK - The network mask. Default: 255.255.255.0
+
+ Other required configuration settings: Of course TCP networking support
+ is required. But here are a couple that are less obvious:
+
+ CONFIG_DISABLE_PTHREAD - pthread support is required
+ CONFIG_DISABLE_POLL - poll() support is required
+
+ Other FTPD configuration options thay may be of interest:
+
+ CONFIG_FTPD_VENDORID - The vendor name to use in FTP communications.
+ Default: "NuttX"
+ CONFIG_FTPD_SERVERID - The server name to use in FTP communications.
+ Default: "NuttX FTP Server"
+ CONFIG_FTPD_CMDBUFFERSIZE - The maximum size of one command. Default:
+ 512 bytes.
+ CONFIG_FTPD_DATABUFFERSIZE - The size of the I/O buffer for data
+ transfers. Default: 2048 bytes.
+ CONFIG_FTPD_WORKERSTACKSIZE - The stacksize to allocate for each
+ FTP daemon worker thread. Default: 2048 bytes.
+
+ The appconfig file (apps/.config) should include:
+
+ CONFIGURED_APPS += examples/ftpd
+ CONFIGURED_APPS += netutils/uiplib
+ CONFIGURED_APPS += netutils/ftpd
+
+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.
+
+ * CONFIG_EXAMPLES_HELLO_BUILTIN
+ Build the "Hello, World" example as an NSH built-in application.
+
+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 prerequisites:
+
+ CONFIG_HAVE_CXX -- Enable C++ Support
+
+ Optional NuttX configuration settings:
+
+ CONFIG_HAVE_CXXINITIALIZE -- Enable support for static constructors
+ (may not be available on all platforms).
+
+ NuttX configuration settings specific to this examp;le:
+
+ CONFIG_EXAMPLES_HELLOXX_BUILTIN -- Build the helloxx example as a
+ "built-in" that can be executed from the NSH command line.
+ 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
+ correctly from an LCD interface. At present, this supports only LCDs
+ with RGB565 color format.
+
+ * CONFIG_EXAMPLES_LDCRW_DEVNO
+ LCD device number. Default: 0
+ * CONFIG_EXAMPLES_LDCRW_XRES
+ LCD X resolution. Default: 240
+ * CONFIG_EXAMPLES_LDCRW_YRES
+ LCD Y resolution. Default: 320
+
+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/modbus
+^^^^^^^^^^^^^^^
+
+ This is a port of the FreeModbus Linux demo. It derives from the
+ demos/LINUX directory of the FreeModBus version 1.5.0 (June 6, 2010)
+ that can be downloaded in its entirety from http://developer.berlios.de/project/showfiles.php?group_id=6120.
+
+ CONFIG_EXAMPLES_MODBUS_PORT, Default 0 (for /dev/ttyS0)
+ CONFIG_EXAMPLES_MODBUS_BAUD, Default B38400
+ CONFIG_EXAMPLES_MODBUS_PARITY, Default MB_PAR_EVEN
+
+ CONFIG_EXAMPLES_MODBUS_REG_INPUT_START, Default 1000
+ CONFIG_EXAMPLES_MODBUS_REG_INPUT_NREGS, Default 4
+ CONFIG_EXAMPLES_MODBUS_REG_HOLDING_START, Default 2000
+ CONFIG_EXAMPLES_MODBUS_REG_HOLDING_NREGS, Default 130
+
+ The FreeModBus library resides at apps/modbus. See apps/modbus/README.txt
+ for additional configuration information.
+
+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
+
+ NOTE: If the NSH serial console is used, then following is also
+ required to build the readline() library:
+
+ CONFIGURED_APPS += system/readline
+
+ And if networking is included:
+
+ CONFIGURED_APPS += uiplib
+ CONFIGURED_APPS += dhcpc
+ CONFIGURED_APPS += resolv
+ CONFIGURED_APPS += tftp
+ CONFIGURED_APPS += webclient
+
+ If the Telnet console is enabled, then the appconfig file (apps/.config)
+ should also include:
+
+ CONFIGURED_APPS += netutils/telnetd
+
+ Also if the Telnet console is enabled, make sure that you have the
+ following set in the NuttX configuration file or else the performance
+ will be very bad (because there will be only one character per TCP
+ transfer):
+
+ CONFIG_STDIO_BUFFER_SIZE - Some value >= 64
+ CONFIG_STDIO_LINEBUFFER=y
+
+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/nxconsole
+^^^^^^^^^^^^^^^^^^
+
+ This directory contains yet another version of the NuttShell (NSH). This
+ version uses the NX console device defined in include/nuttx/nx/nxconsole.h
+ for output. the result is that the NSH input still come from the standard
+ console input (probably a serial console). But the text output will go to
+ an NX winbdow. Prerequisite configuration settings for this test include:
+
+ CONFIG_NX=y -- NX graphics must be enabled
+ CONFIG_NXCONSOLE=y -- The NX console driver must be built
+ CONFIG_NX_MULTIUSER=y -- NX multi-user support must be enabled.
+ CONFIG_DISABLE_MQUEUE=n -- Message queue support must be available.
+ CONFIG_DISABLE_SIGNALS=n -- Signals are needed
+ CONFIG_DISABLE_PTHREAD=n -- pthreads are needed
+ CONFIG_NX_BLOCKING=y -- pthread APIs must be blocking
+ CONFIG_NSH_CONSOLE=y -- NSH must be configured to use a console.
+
+ The following configuration options can be selected to customize the
+ test:
+
+ CONFIG_EXAMPLES_NXCON_VPLANE -- The plane to select from the frame-
+ buffer driver for use in the test. Default: 0
+ CONFIG_EXAMPLES_NXCON_DEVNO - The LCD device to select from the LCD
+ driver for use in the test: Default: 0
+ CONFIG_EXAMPLES_NXCON_BGCOLOR -- The color of the background. Default
+ Default is a darker royal blue.
+ CONFIG_EXAMPLES_NXCON_WCOLOR -- The color of the window. Default is a light
+ slate blue.
+ CONFIG_EXAMPLES_NXCON_FONTID -- Selects the font (see font ID numbers in
+ include/nuttx/nx/nxfonts.h)
+ CONFIG_EXAMPLES_NXCON_FONTCOLOR -- The color of the fonts. Default is
+ black.
+ CONFIG_EXAMPLES_NXCON_BPP -- Pixels per pixel to use. Valid options
+ include 2, 4, 8, 16, 24, and 32. Default is 32.
+ CONFIG_EXAMPLES_NXCON_TOOLBAR_HEIGHT -- The height of the toolbar.
+ Default: 16
+ CONFIG_EXAMPLES_NXCON_TBCOLOR -- The color of the toolbar. Default is
+ a medium grey.
+ CONFIG_EXAMPLES_NXCON_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_NXCON_MINOR -- The NX console device minor number.
+ Default is 0 corresponding to /dev/nxcon0
+ CONFIG_EXAMPLES_NXCON_DEVNAME -- The quoated, full path to the
+ NX console device corresponding to CONFIG_EXAMPLES_NXCON_MINOR.
+ Default: "/dev/nxcon0"
+ CONFIG_EXAMPLES_NXCONSOLE_PRIO - Priority of the NxConsole task.
+ Default: SCHED_PRIORITY_DEFAULT
+ CONFIG_EXAMPLES_NXCONSOLE_STACKSIZE - Stack size allocated for the
+ NxConsole task. Default: 2048
+
+ The following configuration settings determine how to set up the NX
+ server (CONFIG_NX_MULTIUSER):
+
+ CONFIG_EXAMPLES_NXCON_STACKSIZE -- The stacksize to use when creating
+ the NX server. Default 2048
+ CONFIG_EXAMPLES_NXCON_CLIENTPRIO -- The client priority. Default: 100
+ CONFIG_EXAMPLES_NXCON_SERVERPRIO -- The server priority. Default: 120
+ CONFIG_EXAMPLES_NXCON_LISTENERPRIO -- The priority of the event listener
+ thread. Default 80.
+ CONFIG_EXAMPLES_NXCON_NOTIFYSIGNO -- The signal number to use with
+ nx_eventnotify(). Default: 4
+
+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: 16).
+ 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_BUILTIN
+ Build the OS test example as an NSH built-in application.
+ * 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/pwm
+^^^^^^^^^^^^
+
+ A test of a PWM device driver. It simply enables a pulsed output for
+ a specified frequency and duty for a specified period of time. This
+ example can ONLY be built as an NSH built-in function.
+
+ This test depends on these specific PWM/NSH configurations settings (your
+ specific PWM settings might require additional settings).
+
+ CONFIG_PWM - Enables PWM support.
+ CONFIG_EXAMPLES_PWM_COUNT - Enabled PWM pulse count support (if the
+ hardware supports it).
+ CONFIG_NSH_BUILTIN_APPS - Build the PWM test as an NSH built-in function.
+ Default: Not built! The example can only be used as an NSH built-in
+ application
+
+ Specific configuration options for this example include:
+
+ CONFIG_EXAMPLES_PWM_DEVPATH - The path to the default PWM device. Default: /dev/pwm0
+ CONFIG_EXAMPLES_PWM_FREQUENCY - The initial PWM frequency. Default: 100 Hz
+ CONFIG_EXAMPLES_PWM_DUTYPCT - The initial PWM duty as a percentage. Default: 50%
+ CONFIG_EXAMPLES_PWM_DURATION - The initial PWM pulse train duration in seconds.
+ Used only if the current pulse count is zero (pulse count is only supported
+ if CONFIG_PWM_PULSECOUNT is defined). Default: 5 seconds
+ CONFIG_EXAMPLES_PWM_PULSECOUNT - The initial PWM pulse count. This option is
+ only available if CONFIG_PWM_PULSECOUNT is non-zero. Default: 0 (i.e., use
+ the duration, not the count).
+
+examples/qencoder
+^^^^^^^^^^^^^^^^^
+
+ This example is a simple test of a Quadrature Encoder driver. It simply reads
+ positional data from the encoder and prints it.,
+
+ This test depends on these specific QE/NSH configurations settings (your
+ specific PWM settings might require additional settings).
+
+ CONFIG_QENCODER - Enables quadrature encoder support (upper-half driver).
+ CONFIG_NSH_BUILTIN_APPS - Build the QE test as an NSH built-in function.
+ Default: Built as a standalone progrem.
+
+ Additional configuration options will mostly likely be required for the board-
+ specific lower-half driver. See the README.txt file in your board configuration
+ directory.
+
+ Specific configuration options for this example include:
+
+ CONFIG_EXAMPLES_QENCODER_DEVPATH - The path to the QE device. Default:
+ /dev/qe0
+ CONFIG_EXAMPLES_QENCODER_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_QENCODER_DELAY - This value provides the delay (in
+ milliseonds) between each sample. If CONFIG_NSH_BUILTIN_APPS
+ is defined, then this value is the default delay if no other delay is
+ provided on the command line. Default: 100 milliseconds
+
+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 rgmp_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/telnetd
+^^^^^^^^^^^^^^^^
+
+ This directory 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.
+
+ CONFIG_EXAMPLES_TELNETD_DAEMONPRIO - Priority of the Telnet daemon.
+ Default: SCHED_PRIORITY_DEFAULT
+ CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the
+ Telnet daemon. Default: 2048
+ CONFIG_EXAMPLES_TELNETD_CLIENTPRIO- Priority of the Telnet client.
+ Default: SCHED_PRIORITY_DEFAULT
+ CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the
+ Telnet client. Default: 2048
+ CONFIG_EXAMPLE_TELNETD_NOMAC - If the hardware has no MAC address of its
+ own, define this =y to provide a bogus address for testing.
+ CONFIG_EXAMPLE_TELNETD_IPADDR - The target IP address. Default 10.0.0.2
+ CONFIG_EXAMPLE_TELNETD_DRIPADDR - The default router address. Default
+ 10.0.0.1
+ CONFIG_EXAMPLE_TELNETD_NETMASK - The network mask. Default: 255.255.255.0
+
+ The appconfig file (apps/.config) should include:
+
+ CONFIGURED_APPS += examples/telnetd
+ CONFIGURED_APPS += netutils/uiplib
+ CONFIGURED_APPS += netutils/telnetd
+
+ Also, make sure that you have the following set in the NuttX configuration
+ file or else the performance will be very bad (because there will be only
+ one character per TCP transfer):
+
+ CONFIG_STDIO_BUFFER_SIZE - Some value >= 64
+ CONFIG_STDIO_LINEBUFFER=y
+
+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 directory 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
+
+ NOTE: This example does depend on the perl script at
+ nuttx/tools/mkfsdata.pl. You must have perl installed on your
+ development system at /usr/bin/perl.
+
+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 or /dev/ttyACM0 (depending on the configured
+ USB serial driver).
+
+ 3. Then start the host application:
+
+ ./host [<tty-dev>]
+
+ Where:
+
+ <tty-dev> is the USB TTY device to use. The default is
+ "/dev/ttyUSB0" (for the PL2303 emulation) or "/dev/ttyACM0" (for
+ the CDC/ACM serial device).
+
+ 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 usbmsc_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 usbmsc_archinitialize() see
+ configs/mcu123-lpc124x/src/up_usbmsc.c or
+ configs/stm3210e-eval/src/usbmsc.c
+
+ Configuration options:
+
+ CONFIG_EXAMPLES_USBMSC_BUILTIN
+ This example can be built as two NSH "built-in" commands if this option
+ is selected: 'msconn' will connect the USB mass storage device; 'msdis'
+ will disconnect the USB storage device.
+ CONFIG_EXAMPLES_USBMSC_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_USBMSC_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_USBMSC_DEVPATH1
+ The full path to the registered block driver. Default is "/dev/mmcsd0"
+ CONFIG_EXAMPLES_USBMSC_DEVMINOR2 and CONFIG_EXAMPLES_USBMSC_DEVPATH2
+ Similar parameters that would have to be provided if CONFIG_EXAMPLES_USBMSC_NLUNS
+ is 2 or 3. No defaults.
+ CONFIG_EXAMPLES_USBMSC_DEVMINOR3 and CONFIG_EXAMPLES_USBMSC_DEVPATH3
+ Similar parameters that would have to be provided if CONFIG_EXAMPLES_USBMSC_NLUNS
+ is 3. No defaults.
+ CONFIG_EXAMPLES_USBMSC_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_USBMSC_TRACEINIT
+ Show initialization events
+ CONFIG_EXAMPLES_USBMSC_TRACECLASS
+ Show class driver events
+ CONFIG_EXAMPLES_USBMSC_TRACETRANSFERS
+ Show data transfer events
+ CONFIG_EXAMPLES_USBMSC_TRACECONTROLLER
+ Show controller events
+ CONFIG_EXAMPLES_USBMSC_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_USBMSC_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_USBTERM_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_DEVINIT - If defined, then the example will
+ call a user provided function as part of its initialization:
+ int usbterm_devinit(void);
+ And another user provided function at termination:
+ void usbterm_devuninit(void);
+ 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.
+
+ NOTE: By default, USBterm uses readline to get data from stdin. So your
+ appconfig file must have the following build path:
+
+ CONFIGURED_APPS += system/readline
+
+ NOTE: If you use the USBterm task over a telnet NSH connection, then you
+ should set the following configuration item:
+
+ CONFIG_EXAMPLES_USBTERM_FGETS=y
+
+ By default, the USBterm client will use readline() to get characters from
+ the console. Readline includes and command-line editor and echos
+ characters received in stdin back through stdout. Neither of these
+ behaviors are desire-able if Telnet is used.
+
+ Error results are always shown in the trace output
+
+ Other relevant configuration options: CONFIG_CDCACM selected by the
+ Prolifics emulation (not defined) and the CDC serial implementation
+ (when defined). CONFIG_USBDEV_TRACE_INITIALIDSET.
+
+examples/watchdog
+^^^^^^^^^^^^^^^^^
+
+ A simple test of a watchdog timer driver. Initializes starts the watchdog
+ timer. It pings the watchdog timer for a period of time then lets the
+ watchdog timer expire... resetting the CPU is successful. This
+ example can ONLY be built as an NSH built-in function.
+
+ This test depends on these specific Watchdog/NSH configurations settings (your
+ specific watchdog hardware settings might require additional settings).
+
+ CONFIG_WATCHDOG- Enables watchdog timer support support.
+ CONFIG_NSH_BUILTIN_APPS - Build the watchdog time test as an NSH
+ built-in function. Default: Not built! The example can only be used
+ as an NSH built-in application
+
+ Specific configuration options for this example include:
+
+ CONFIG_EXAMPLES_WATCHDOG_DEVPATH - The path to the Watchdog device.
+ Default: /dev/watchdog0
+ CONFIG_EXAMPLES_WATCHDOG_PINGTIME - Time in milliseconds that the example
+ will ping the watchdog before letting the watchdog expire. Default: 5000
+ milliseconds
+ CONFIG_EXAMPLES_WATCHDOG_PINGDELAY - Time delay between pings in
+ milliseconds. Default: 500 milliseconds.
+ CONFIG_EXAMPLES_WATCHDOG_TIMEOUT - The watchdog timeout value in
+ milliseconds before the watchdog timer expires. Default: 2000
+ milliseconds.
+
+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
+
+examples/xmlrpc
+
+ This example exercises the "Embeddable Lightweight XML-RPC Server" which
+ is discussed at:
+
+ http://www.drdobbs.com/web-development/an-embeddable-lightweight-xml-rpc-server/184405364
+
+ Configuration options:
+
+ CONFIG_EXAMPLES_XMLRPC_BUFFERSIZE - HTTP buffer size. Default 1024
+ CONFIG_EXAMPLES_XMLRPC_DHCPC - Use DHCP Client. Default n. Ignored
+ if CONFIG_NSH_BUILTIN_APPS is selected.
+ CONFIG_EXAMPLES_XMLRPC_NOMAC - Use Canned MAC Address. Defaul n. Ignored
+ if CONFIG_NSH_BUILTIN_APPS is selected.
+ CONFIG_EXAMPLES_XMLRPC_IPADDR - Target IP address. Default 0x0a000002.
+ Ignored if CONFIG_NSH_BUILTIN_APPS is selected.
+ CONFIG_EXAMPLES_XMLRPC_DRIPADDR - Default Router IP address (Gateway).
+ Default 0x0a000001. Ignored if CONFIG_NSH_BUILTIN_APPS is selected.
+ CONFIG_EXAMPLES_XMLRPC_NETMASK - Network Mask. Default 0xffffff00
+ Ignored if CONFIG_NSH_BUILTIN_APPS is selected.
diff --git a/apps/examples/adc/Kconfig b/apps/examples/adc/Kconfig
new file mode 100644
index 000000000..b6dca047c
--- /dev/null
+++ b/apps/examples/adc/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_ADC
+ bool "ADC example"
+ default n
+ ---help---
+ Enable the ADC example
+
+if EXAMPLES_ADC
+endif
diff --git a/apps/examples/adc/Makefile b/apps/examples/adc/Makefile
new file mode 100644
index 000000000..6357dfc3d
--- /dev/null
+++ b/apps/examples/adc/Makefile
@@ -0,0 +1,105 @@
+############################################################################
+# apps/examples/adc/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
+
+# 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 100644
index 000000000..9f79db92a
--- /dev/null
+++ b/apps/examples/adc/adc.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+ * examples/examples/adc/adc.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#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 default 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
+ ****************************************************************************/
+
+struct adc_state_s
+{
+ bool initialized;
+ FAR char *devpath;
+#if defined(CONFIG_NSH_BUILTIN_APPS) || defined(CONFIG_EXAMPLES_ADC_NSAMPLES)
+ int count;
+#endif
+};
+
+/****************************************************************************
+ * 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..4797265db
--- /dev/null
+++ b/apps/examples/adc/adc_main.c
@@ -0,0 +1,359 @@
+/****************************************************************************
+ * examples/adc/adc_main.c
+ *
+ * Copyright (C) 2011-2012 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 <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/analog/adc.h>
+
+#include "adc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct adc_state_s g_adcstate;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: adc_devpath
+ ****************************************************************************/
+
+static void adc_devpath(FAR struct adc_state_s *adc, FAR const char *devpath)
+{
+ /* Get rid of any old device path */
+
+ if (adc->devpath)
+ {
+ free(adc->devpath);
+ }
+
+ /* Then set-up the new device path by copying the string */
+
+ adc->devpath = strdup(devpath);
+}
+
+/****************************************************************************
+ * Name: adc_help
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+static void adc_help(FAR struct adc_state_s *adc)
+{
+ message("Usage: adc [OPTIONS]\n");
+ message("\nArguments are \"sticky\". For example, once the ADC device is\n");
+ message("specified, that device will be re-used until it is changed.\n");
+ message("\n\"sticky\" OPTIONS include:\n");
+ message(" [-p devpath] selects the ADC device. "
+ "Default: %s Current: %s\n",
+ CONFIG_EXAMPLES_ADC_DEVPATH, g_adcstate.devpath ? g_adcstate.devpath : "NONE");
+ message(" [-n count] selects the samples to collect. "
+ "Default: 1 Current: %d\n", adc->count);
+ message(" [-h] shows this message and exits\n");
+}
+#endif
+
+/****************************************************************************
+ * Name: arg_string
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+static 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;
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: arg_decimal
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+static 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;
+}
+#endif
+
+/****************************************************************************
+ * Name: parse_args
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+static void parse_args(FAR struct adc_state_s *adc, int argc, FAR char **argv)
+{
+ FAR char *ptr;
+ FAR char *str;
+ long value;
+ int index;
+ int nargs;
+
+ for (index = 1; index < argc; )
+ {
+ ptr = argv[index];
+ if (ptr[0] != '-')
+ {
+ message("Invalid options format: %s\n", ptr);
+ exit(0);
+ }
+
+ switch (ptr[1])
+ {
+ case 'n':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 0)
+ {
+ message("Count must be non-negative: %ld\n", value);
+ exit(1);
+ }
+
+ adc->count = (uint32_t)value;
+ index += nargs;
+ break;
+
+ case 'p':
+ nargs = arg_string(&argv[index], &str);
+ adc_devpath(adc, str);
+ index += nargs;
+ break;
+
+ case 'h':
+ adc_help(adc);
+ exit(0);
+
+ default:
+ message("Unsupported option: %s\n", ptr);
+ adc_help(adc);
+ exit(1);
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: adc_main
+ ****************************************************************************/
+
+int adc_main(int argc, char *argv[])
+{
+ struct adc_msg_s sample[CONFIG_EXAMPLES_ADC_GROUPSIZE];
+ size_t readsize;
+ ssize_t nbytes;
+ int fd;
+ int errval = 0;
+ int ret;
+ int i;
+
+ /* Check if we have initialized */
+
+ if (!g_adcstate.initialized)
+ {
+ /* Initialization of the ADC hardware is performed by logic external to
+ * this test.
+ */
+
+ message("adc_main: Initializing external ADC device\n");
+ ret = adc_devinit();
+ if (ret != OK)
+ {
+ message("adc_main: adc_devinit failed: %d\n", ret);
+ errval = 1;
+ goto errout;
+ }
+
+ /* Set the default values */
+
+ adc_devpath(&g_adcstate, CONFIG_EXAMPLES_ADC_DEVPATH);
+
+#ifdef CONFIG_EXAMPLES_ADC_NSAMPLES
+ g_adcstate.count = CONFIG_EXAMPLES_ADC_NSAMPLES;
+#else
+ g_adcstate.count = 1;
+#endif
+ g_adcstate.initialized = true;
+ }
+
+ /* Parse the command line */
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ parse_args(&g_adcstate, argc, argv);
+#endif
+
+ /* 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) || defined(CONFIG_EXAMPLES_ADC_NSAMPLES)
+ message("adc_main: g_adcstate.count: %d\n", g_adcstate.count);
+#endif
+
+ /* Open the ADC device for reading */
+
+ message("adc_main: Hardware initialized. Opening the ADC device: %s\n",
+ g_adcstate.devpath);
+
+ fd = open(g_adcstate.devpath, O_RDONLY);
+ if (fd < 0)
+ {
+ message("adc_main: open %s failed: %d\n", g_adcstate.devpath, errno);
+ errval = 2;
+ goto errout_with_dev;
+ }
+
+ /* Now loop the appropriate number of times, displaying the collected
+ * ADC samples.
+ */
+
+#if defined(CONFIG_NSH_BUILTIN_APPS)
+ for (; g_adcstate.count > 0; g_adcstate.count--)
+#elif defined(CONFIG_EXAMPLES_ADC_NSAMPLES)
+ for (g_adcstate.count = 0; g_adcstate.count < CONFIG_EXAMPLES_ADC_NSAMPLES; g_adcstate.count++)
+#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);
+
+ /* Handle unexpected return values */
+
+ if (nbytes < 0)
+ {
+ errval = errno;
+ if (errval != EINTR)
+ {
+ message("adc_main: read %s failed: %d\n",
+ g_adcstate.devpath, errval);
+ errval = 3;
+ goto errout_with_dev;
+ }
+
+ message("adc_main: Interrupted read...\n");
+ }
+ else if (nbytes == 0)
+ {
+ message("adc_main: No data read, Ignoring\n");
+ }
+
+ /* Print the sample data on successful return */
+
+ else
+ {
+ int nsamples = nbytes / sizeof(struct adc_msg_s);
+ if (nsamples * sizeof(struct adc_msg_s) != nbytes)
+ {
+ message("adc_main: read size=%d is not a multiple of sample size=%d, Ignoring\n",
+ nbytes, sizeof(struct adc_msg_s));
+ }
+ else
+ {
+ message("Sample:\n");
+ for (i = 0; i < nsamples ; 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/Kconfig b/apps/examples/buttons/Kconfig
new file mode 100644
index 000000000..9c34b37bc
--- /dev/null
+++ b/apps/examples/buttons/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_BUTTONS
+ bool "Buttons example"
+ default n
+ ---help---
+ Enable the buttons example
+
+if EXAMPLES_BUTTONS
+endif
diff --git a/apps/examples/buttons/Makefile b/apps/examples/buttons/Makefile
new file mode 100644
index 000000000..25d1ef2c2
--- /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 <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
+
+# Hello, World! Example
+
+ASRCS =
+CSRCS = buttons_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/buttons_main.c b/apps/examples/buttons/buttons_main.c
new file mode 100644
index 000000000..a3f6449d4
--- /dev/null
+++ b/apps/examples/buttons/buttons_main.c
@@ -0,0 +1,499 @@
+/****************************************************************************
+ * examples/buttons/buttons_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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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)
+
+/****************************************************************************
+ * 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
+ ****************************************************************************/
+
+/****************************************************************************
+ * buttons_main
+ ****************************************************************************/
+
+int buttons_main(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
+
+ /* Initialize the button GPIOs */
+
+ up_buttoninit();
+
+ /* 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/can/Kconfig b/apps/examples/can/Kconfig
new file mode 100644
index 000000000..2b4504d68
--- /dev/null
+++ b/apps/examples/can/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_CAN
+ bool "CAN example"
+ default n
+ ---help---
+ Enable the CAN example
+
+if EXAMPLES_CAN
+endif
+
diff --git a/apps/examples/can/Makefile b/apps/examples/can/Makefile
new file mode 100644
index 000000000..c6dc5af84
--- /dev/null
+++ b/apps/examples/can/Makefile
@@ -0,0 +1,105 @@
+############################################################################
+# apps/examples/can/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
+
+# NuttX NX Graphics Example.
+
+ASRCS =
+CSRCS = can_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 = can
+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/can/can.h b/apps/examples/can/can.h
new file mode 100644
index 000000000..53a6b63ea
--- /dev/null
+++ b/apps/examples/can/can.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+ * examples/examples/can/can.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_EXAMPLES_CAN_CAN_H
+#define __APPS_EXAMPLES_CAN_CAN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* This test depends on these specific CAN configurations settings (your
+ * specific CAN settings might require additional settings).
+ *
+ * CONFIG_CAN - Enables CAN support.
+ * CONFIG_CAN_LOOPBACK - A CAN driver may or may not support a loopback
+ * mode for testing. The STM32 CAN driver does support loopback mode.
+ *
+ * Specific configuration options for this example include:
+ *
+ * CONFIG_NSH_BUILTIN_APPS - Build the CAN test as an NSH built-in function.
+ * Default: Built as a standalone problem
+ * CONFIG_CAN_LOOPBACK
+ * CONFIG_EXAMPLES_CAN_DEVPATH - The path to the CAN device. Default: /dev/can0
+ * CONFIG_EXAMPLES_CAN_NMSGS - If CONFIG_NSH_BUILTIN_APPS
+ * is defined, then the number of loops is provided on the command line
+ * and this value is ignored. Otherwise, this number of CAN message is
+ * collected and the program terminates. Default: If built as an NSH
+ * built-in, the default is 32. Otherwise messages are sent and received
+ * indefinitely.
+ * CONFIG_EXAMPLES_CAN_READONLY - Only receive messages
+ * CONFIG_EXAMPLES_CAN_WRITEONLY - Only send messages
+ */
+
+#ifndef CONFIG_CAN
+# error "CAN device support is not enabled (CONFIG_CAN)"
+#endif
+
+#ifndef CONFIG_CAN_LOOPBACK
+# warning "CAN loopback is not enabled (CONFIG_CAN_LOOPBACK)"
+#endif
+
+#ifndef CONFIG_EXAMPLES_CAN_DEVPATH
+# define CONFIG_EXAMPLES_CAN_DEVPATH "/dev/can0"
+#endif
+
+#if defined(CONFIG_NSH_BUILTIN_APPS) && !defined(CONFIG_EXAMPLES_CAN_NMSGS)
+# define CONFIG_EXAMPLES_CAN_NMSGS 32
+#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: can_devinit()
+ *
+ * Description:
+ * Perform architecuture-specific initialization of the CAN hardware. This
+ * interface must be provided by all configurations using apps/examples/can
+ *
+ ****************************************************************************/
+
+int can_devinit(void);
+
+#endif /* __APPS_EXAMPLES_CAN_CAN_H */
diff --git a/apps/examples/can/can_main.c b/apps/examples/can/can_main.c
new file mode 100644
index 000000000..482d3f438
--- /dev/null
+++ b/apps/examples/can/can_main.c
@@ -0,0 +1,301 @@
+/****************************************************************************
+ * examples/can/can_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/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/can.h>
+
+#include "can.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_EXAMPLES_CAN_READONLY)
+# undef CONFIG_EXAMPLES_CAN_WRITEONLY
+# undef CONFIG_EXAMPLES_CAN_READWRITE
+# define CAN_OFLAGS O_RDONLY
+#elif defined(CONFIG_EXAMPLES_CAN_WRITEONLY)
+# undef CONFIG_EXAMPLES_CAN_READWRITE
+# define CAN_OFLAGS O_WRONLY
+#else
+# undef CONFIG_EXAMPLES_CAN_READWRITE
+# define CONFIG_EXAMPLES_CAN_READWRITE 1
+# define CAN_OFLAGS O_RDWR
+#endif
+
+#ifdef CONFIG_CAN_EXTID
+# define MAX_ID (1 << 29)
+#else
+# define MAX_ID (1 << 11)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_main
+ ****************************************************************************/
+
+int can_main(int argc, char *argv[])
+{
+#ifndef CONFIG_EXAMPLES_CAN_READONLY
+ struct can_msg_s txmsg;
+#ifdef CONFIG_CAN_EXTID
+ uint32_t msgid;
+#else
+ uint16_t msgid;
+#endif
+ int msgdlc;
+ uint8_t msgdata;
+#endif
+
+#ifndef CONFIG_EXAMPLES_CAN_WRITEONLY
+ struct can_msg_s rxmsg;
+#endif
+
+ size_t msgsize;
+ ssize_t nbytes;
+#if defined(CONFIG_NSH_BUILTIN_APPS) || defined(CONFIG_EXAMPLES_CAN_NMSGS)
+ long nmsgs;
+#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)
+ nmsgs = CONFIG_EXAMPLES_CAN_NMSGS;
+ if (argc > 1)
+ {
+ nmsgs = strtol(argv[1], NULL, 10);
+ }
+ message("can_main: nmsgs: %d\n", nmsgs);
+#elif defined(CONFIG_EXAMPLES_CAN_NMSGS)
+ message("can_main: nmsgs: %d\n", CONFIG_EXAMPLES_CAN_NMSGS);
+#endif
+
+ /* Initialization of the CAN hardware is performed by logic external to
+ * this test.
+ */
+
+ message("can_main: Initializing external CAN device\n");
+ ret = can_devinit();
+ if (ret != OK)
+ {
+ message("can_main: can_devinit failed: %d\n", ret);
+ errval = 1;
+ goto errout;
+ }
+
+ /* Open the CAN device for reading */
+
+ message("can_main: Hardware initialized. Opening the CAN device\n");
+ fd = open(CONFIG_EXAMPLES_CAN_DEVPATH, CAN_OFLAGS);
+ if (fd < 0)
+ {
+ message("can_main: open %s failed: %d\n",
+ CONFIG_EXAMPLES_CAN_DEVPATH, errno);
+ errval = 2;
+ goto errout_with_dev;
+ }
+
+ /* Now loop the appropriate number of times, performing one loopback test
+ * on each pass.
+ */
+
+#ifndef CONFIG_EXAMPLES_CAN_READONLY
+ msgdlc = 1;
+ msgid = 1;
+ msgdata = 0;
+#endif
+
+#if defined(CONFIG_NSH_BUILTIN_APPS)
+ for (; nmsgs > 0; nmsgs--)
+#elif defined(CONFIG_EXAMPLES_CAN_NMSGS)
+ for (nmsgs = 0; nmsgs < CONFIG_EXAMPLES_CAN_NMSGS; nmsgs++)
+#else
+ for (;;)
+#endif
+ {
+ /* Flush any output before the loop entered or from the previous pass
+ * through the loop.
+ */
+
+ msgflush();
+
+ /* Construct the next TX message */
+
+#ifndef CONFIG_EXAMPLES_CAN_READONLY
+ txmsg.cm_hdr.ch_id = msgid;
+ txmsg.cm_hdr.ch_rtr = false;
+ txmsg.cm_hdr.ch_dlc = msgdlc;
+#ifdef CONFIG_CAN_EXTID
+ txmsg.cm_hdr.ch_extid = true;
+#endif
+
+ for (i = 0; i < msgdlc; i++)
+ {
+ txmsg.cm_data[i] = msgdata + i;
+ }
+
+ /* Send the TX message */
+
+ msgsize = CAN_MSGLEN(msgdlc);
+ nbytes = write(fd, &txmsg, msgsize);
+ if (nbytes != msgsize)
+ {
+ message("ERROR: write(%d) returned %d\n", msgsize, nbytes);
+ errval = 3;
+ goto errout_with_dev;
+ }
+#endif
+
+#ifdef CONFIG_EXAMPLES_CAN_WRITEONLY
+ message(" ID: %4d DLC: %d\n", msgid, msgdlc);
+#endif
+
+ /* Read the RX message */
+
+#ifndef CONFIG_EXAMPLES_CAN_WRITEONLY
+ msgsize = sizeof(struct can_msg_s);
+ nbytes = read(fd, &rxmsg, msgsize);
+ if (nbytes < CAN_MSGLEN(0) || nbytes > msgsize)
+ {
+ message("ERROR: read(%d) returned %d\n", msgsize, nbytes);
+ errval = 4;
+ goto errout_with_dev;
+ }
+#endif
+
+#ifndef CONFIG_EXAMPLES_CAN_READONLY
+ message(" ID: %4d DLC: %d\n", rxmsg.cm_hdr.id, rxmsg.cm_hdr.dlc);
+#endif
+
+ /* Verify that the received messages are the same */
+
+#ifdef CONFIG_EXAMPLES_CAN_READWRITE
+ if (memcmp(&txmsg.cm_hdr, &rxmsg.cm_hdr, sizeof(struct can_hdr_s)) != 0)
+ {
+ message("ERROR: Sent header does not match received header:\n");
+ lib_dumpbuffer("Sent header", (FAR const uint8_t*)&txmsg.cm_hdr,
+ sizeof(struct can_hdr_s));
+ lib_dumpbuffer("Received header", (FAR const uint8_t*)&rxmsg.cm_hdr,
+ sizeof(struct can_hdr_s));
+ errval = 4;
+ goto errout_with_dev;
+ }
+
+ if (memcmp(txmsg.cm_data, rxmsg.cm_data, msgdlc) != 0)
+ {
+ message("ERROR: Data does not match. DLC=%d\n", msgdlc);
+ for (i = 0; i < msgdlc; i++)
+ {
+ message(" %d: TX %02x RX %02x\n", i, txmsg.cm_data[i], rxmsg.cm_data[i]);
+ errval = 5;
+ goto errout_with_dev;
+ }
+ }
+
+ /* Report success */
+
+ message(" ID: %4d DLC: %d -- OK\n", msgid, msgdlc);
+#endif
+
+ /* Set up for the next pass */
+
+#ifndef CONFIG_EXAMPLES_CAN_READONLY
+ msgdata += msgdlc;
+
+ if (++msgid >= MAX_ID)
+ {
+ msgid = 1;
+ }
+
+ if (++msgdlc > CAN_MAXDATALEN)
+ {
+ msgdlc = 1;
+ }
+#endif
+ }
+
+errout_with_dev:
+ close(fd);
+
+errout:
+ message("Terminating!\n");
+ msgflush();
+ return errval;
+}
diff --git a/apps/examples/cdcacm/Kconfig b/apps/examples/cdcacm/Kconfig
new file mode 100644
index 000000000..8cd9c6e99
--- /dev/null
+++ b/apps/examples/cdcacm/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_CDCACM
+ bool "CAN example"
+ default n
+ ---help---
+ Enable the USB CDC/ACM class driver example
+
+if EXAMPLES_CDCACM
+endif
+
diff --git a/apps/examples/cdcacm/Makefile b/apps/examples/cdcacm/Makefile
new file mode 100644
index 000000000..3fa886d56
--- /dev/null
+++ b/apps/examples/cdcacm/Makefile
@@ -0,0 +1,109 @@
+############################################################################
+# apps/examples/cdcacm/Makefile
+#
+# Copyright (C) 2012 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
+
+# USB CDC/ACM serial mass storage example
+
+ASRCS =
+CSRCS = cdcacm_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 CDC/ACM built-in application info
+
+APPNAME1 = sercon
+PRIORITY1 = SCHED_PRIORITY_DEFAULT
+STACKSIZE1 = 2048
+
+APPNAME2 = serdis
+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:
+ $(call REGISTER,$(APPNAME1),$(PRIORITY1),$(STACKSIZE1),$(APPNAME1)_main)
+ $(call REGISTER,$(APPNAME2),$(PRIORITY2),$(STACKSIZE2),$(APPNAME2)_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/examples/cdcacm/cdcacm.h b/apps/examples/cdcacm/cdcacm.h
new file mode 100644
index 000000000..18570bff0
--- /dev/null
+++ b/apps/examples/cdcacm/cdcacm.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+ * examples/cdcacm/cdcacm.h
+ *
+ * Copyright (C) 2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __EXAMPLES_CDCACM_CDCACM_H
+#define __EXAMPLES_CDCACM_CDCACM_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdlib.h>
+
+#include <nuttx/usb/usbdev_trace.h>
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* Prerequisites */
+
+#ifndef CONFIG_USBDEV
+# error "CONFIG_USBDEV is not defined"
+#endif
+
+#ifndef CONFIG_CDCACM
+# error "CONFIG_CDCACM is not defined"
+#endif
+
+#ifndef CONFIG_NSH_BUILTIN_APPS
+# error "This example can only be built as an NSH built-in application"
+#endif
+
+/* Default configuration values */
+
+#ifndef CONFIG_EXAMPLES_CDCACM_DEVMINOR
+# define CONFIG_EXAMPLES_CDCACM_DEVMINOR 0
+#endif
+
+/* Trace Configuration ******************************************************/
+
+#ifdef CONFIG_EXAMPLES_CDCACM_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_CDCACM_TRACECLASS
+# define TRACE_CLASS_BITS (TRACE_CLASS_BIT|TRACE_CLASSAPI_BIT|TRACE_CLASSSTATE_BIT)
+#else
+# define TRACE_CLASS_BITS (0)
+#endif
+
+#ifdef CONFIG_EXAMPLES_CDCACM_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_CDCACM_TRACECONTROLLER
+# define TRACE_CONTROLLER_BITS (TRACE_EP_BIT|TRACE_DEV_BIT)
+#else
+# define TRACE_CONTROLLER_BITS (0)
+#endif
+
+#ifdef CONFIG_EXAMPLES_CDCACM_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_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.
+ */
+
+struct cdcacm_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_NSH_BUILTIN_APPS. In this case, the value
+ * of the driver handle must be remembered between the 'sercon' and 'msdis'
+ * commands.
+ */
+
+ FAR void *handle;
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* All global variables used by this example are packed into a structure in
+ * order to avoid name collisions.
+ */
+
+extern struct cdcacm_state_s g_cdcacm;
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#endif /* __EXAMPLES_CDCACM_CDCACM_H */
diff --git a/apps/examples/cdcacm/cdcacm_main.c b/apps/examples/cdcacm/cdcacm_main.c
new file mode 100644
index 000000000..aeb7a9e74
--- /dev/null
+++ b/apps/examples/cdcacm/cdcacm_main.c
@@ -0,0 +1,147 @@
+/****************************************************************************
+ * examples/cdcacm/cdcacm_main.c
+ *
+ * Copyright (C) 2012 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 <debug.h>
+
+#include <nuttx/usb/usbdev.h>
+#include <nuttx/usb/cdcacm.h>
+
+#include "cdcacm.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* All global variables used by this example are packed into a structure in
+ * order to avoid name collisions.
+ */
+
+struct cdcacm_state_s g_cdcacm;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * sercon_main
+ *
+ * Description:
+ * This is the main program that configures the CDC/ACM serial device.
+ *
+ ****************************************************************************/
+
+int sercon_main(int argc, char *argv[])
+{
+ int ret;
+
+ /* Check if there is a non-NULL USB mass storage device handle (meaning that the
+ * USB mass storage device is already configured).
+ */
+
+ if (g_cdcacm.handle)
+ {
+ message("sercon:: ERROR: Already connected\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Then, in any event, enable trace data collection as configured BEFORE
+ * enabling the CDC/ACM device.
+ */
+
+ usbtrace_enable(TRACE_BITSET);
+
+ /* Initialize the USB CDC/ACM serial driver */
+
+ message("sercon: Registering CDC/ACM serial driver\n");
+ ret = cdcacm_initialize(CONFIG_EXAMPLES_CDCACM_DEVMINOR, &g_cdcacm.handle);
+ if (ret < 0)
+ {
+ message("sercon: ERROR: Failed to create the CDC/ACM serial device: %d\n", -ret);
+ return EXIT_FAILURE;
+ }
+
+ message("sercon: Successfully registered the CDC/ACM serial driver\n");
+ return EXIT_SUCCESS;
+}
+
+/****************************************************************************
+ * serdis_main
+ *
+ * Description:
+ * This is a program entry point that will disconnect the CDC/ACM serial
+ * device.
+ *
+ ****************************************************************************/
+
+int serdis_main(int argc, char *argv[])
+{
+ /* First check if the USB mass storage device is already connected */
+
+ if (!g_cdcacm.handle)
+ {
+ message("serdis: ERROR: Not connected\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Then, in any event, disable trace data collection as configured BEFORE
+ * enabling the CDC/ACM device.
+ */
+
+ usbtrace_enable(0);
+
+ /* Then disconnect the device and uninitialize the USB mass storage driver */
+
+ cdcacm_uninitialize(g_cdcacm.handle);
+ g_cdcacm.handle = NULL;
+ message("serdis: Disconnected\n");
+ return EXIT_SUCCESS;
+}
diff --git a/apps/examples/composite/Kconfig b/apps/examples/composite/Kconfig
new file mode 100644
index 000000000..d2d62043c
--- /dev/null
+++ b/apps/examples/composite/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_COMPOSITE
+ bool "USB composite class driver example"
+ default n
+ ---help---
+ Enable the USB compsite class driver example
+
+if EXAMPLES_COMPOSITE
+endif
+
diff --git a/apps/examples/composite/Makefile b/apps/examples/composite/Makefile
new file mode 100644
index 000000000..17c9f6d18
--- /dev/null
+++ b/apps/examples/composite/Makefile
@@ -0,0 +1,111 @@
+############################################################################
+# apps/examples/composite/Makefile
+#
+# Copyright (C) 2012 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
+
+# USB device mass storage example
+
+ASRCS =
+CSRCS = composite_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 = conn
+PRIORITY1 = SCHED_PRIORITY_DEFAULT
+STACKSIZE1 = 2048
+
+APPNAME2 = disconn
+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_NSH_BUILTIN_APPS),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/composite/composite.h b/apps/examples/composite/composite.h
new file mode 100644
index 000000000..73a4453be
--- /dev/null
+++ b/apps/examples/composite/composite.h
@@ -0,0 +1,259 @@
+/****************************************************************************
+ * examples/composite/composite.h
+ *
+ * Copyright (C) 2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __EXAMPLES_COMPOSITE_COMPOSITE_H
+#define __EXAMPLES_COMPOSITE_COMPOSITE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdlib.h>
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* OS/Driver configuration checkes */
+
+#ifndef CONFIG_USBDEV
+# error "USB device support is not enabled (CONFIG_USBDEV)"
+#endif
+
+#ifndef CONFIG_USBDEV_COMPOSITE
+# error "USB composite device support is not enabled (CONFIG_USBDEV_COMPOSITE)"
+#endif
+
+#ifndef CONFIG_CDCACM
+# error "USB CDC/ACM serial device support is not enabled (CONFIG_CDCACM)"
+#endif
+
+#ifndef CONFIG_CDCACM_COMPOSITE
+# error "USB CDC/ACM serial composite device support is not enabled (CONFIG_CDCACM_COMPOSITE)"
+#endif
+
+#ifndef CONFIG_USBMSC
+# error "USB mass storage device support is not enabled (CONFIG_USBMSC)"
+#endif
+
+#ifndef CONFIG_USBMSC_COMPOSITE
+# error "USB mass storage composite device support is not enabled (CONFIG_USBMSC_COMPOSITE)"
+#endif
+
+/* Example MSC default values */
+
+#ifndef CONFIG_EXAMPLES_COMPOSITE_NLUNS
+# define CONFIG_EXAMPLES_COMPOSITE_NLUNS 1
+#endif
+
+#ifndef CONFIG_EXAMPLES_COMPOSITE_DEVMINOR1
+# define CONFIG_EXAMPLES_COMPOSITE_DEVMINOR1 0
+#endif
+
+#ifndef CONFIG_EXAMPLES_COMPOSITE_DEVPATH1
+# define CONFIG_EXAMPLES_COMPOSITE_DEVPATH1 "/dev/mmcsd0"
+#endif
+
+#if CONFIG_EXAMPLES_COMPOSITE_NLUNS > 1
+# ifndef CONFIG_EXAMPLES_COMPOSITE_DEVMINOR2
+# error "CONFIG_EXAMPLES_COMPOSITE_DEVMINOR2 for LUN=2"
+# endif
+# ifndef CONFIG_EXAMPLES_COMPOSITE_DEVPATH2
+# error "CONFIG_EXAMPLES_COMPOSITE_DEVPATH2 for LUN=2"
+# endif
+# if CONFIG_EXAMPLES_COMPOSITE_NLUNS > 2
+# ifndef CONFIG_EXAMPLES_COMPOSITE_DEVMINOR3
+# error "CONFIG_EXAMPLES_COMPOSITE_DEVMINOR2 for LUN=3"
+# endif
+# ifndef CONFIG_EXAMPLES_COMPOSITE_DEVPATH2
+# error "CONFIG_EXAMPLES_COMPOSITE_DEVPATH2 for LUN=3"
+# endif
+# if CONFIG_EXAMPLES_COMPOSITE_NLUNS > 3
+# error "CONFIG_EXAMPLES_COMPOSITE_NLUNS must be {1,2,3}"
+# endif
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_COMPOSITE_BUFLEN
+# define CONFIG_EXAMPLES_COMPOSITE_BUFLEN 256
+#endif
+
+/* Example MSC default values */
+
+#ifndef CONFIG_EXAMPLES_COMPOSITE_TTYUSB
+# define CONFIG_EXAMPLES_COMPOSITE_TTYUSB 0
+#endif
+
+#ifndef CONFIG_EXAMPLES_COMPOSITE_SERDEV
+# if CONFIG_EXAMPLES_COMPOSITE_TTYUSB != 0
+# error "Serial device unknown (CONFIG_EXAMPLES_COMPOSITE_SERDEV)"
+# elif defined(CONFIG_CDCACM)
+# define CONFIG_EXAMPLES_COMPOSITE_SERDEV "/dev/ttyACM0"
+# else
+# define CONFIG_EXAMPLES_COMPOSITE_SERDEV "/dev/ttyUSB0"
+# endif
+#endif
+
+#ifndef CONFIG_EXAMPLES_COMPOSITE_BUFSIZE
+# define CONFIG_EXAMPLES_COMPOSITE_BUFSIZE 256
+#endif
+
+/* Trace initialization *****************************************************/
+
+#ifdef CONFIG_EXAMPLES_COMPOSITE_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_COMPOSITE_TRACECLASS
+# define TRACE_CLASS_BITS (TRACE_CLASS_BIT|TRACE_CLASSAPI_BIT|TRACE_CLASSSTATE_BIT)
+#else
+# define TRACE_CLASS_BITS (0)
+#endif
+
+#ifdef CONFIG_EXAMPLES_COMPOSITE_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_COMPOSITE_TRACECONTROLLER
+# define TRACE_CONTROLLER_BITS (TRACE_EP_BIT|TRACE_DEV_BIT)
+#else
+# define TRACE_CONTROLLER_BITS (0)
+#endif
+
+#ifdef CONFIG_EXAMPLES_COMPOSITE_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_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.
+ */
+
+struct composite_state_s
+{
+ /* This is the handle that references to this particular USB composite driver
+ * instance. It is only needed if the example is built using
+ * CONFIG_NSH_BUILTIN_APPS. In this case, the value of the driver handle
+ * must be remembered between the 'conn' and 'disconn' commands.
+ */
+
+ FAR void *cmphandle; /* Composite device handle */
+ FAR void *mschandle; /* Mass storage device handle */
+
+ /* Serial file descriptors */
+
+#if !defined(CONFIG_NSH_BUILTIN_APPS) || defined(CONFIG_DISABLE_SIGNALS)
+ int outfd; /* Blocking write-only */
+ int infd; /* Non-blockig read-only */
+#endif
+
+ /* Heap usage samples. These are useful for checking USB storage memory
+ * usage and for tracking down memoryh leaks.
+ */
+
+#ifdef CONFIG_EXAMPLES_COMPOSITE_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
+
+ /* Serial I/O buffer */
+
+#if !defined(CONFIG_NSH_BUILTIN_APPS) || defined(CONFIG_DISABLE_SIGNALS)
+ uint8_t serbuf[CONFIG_EXAMPLES_COMPOSITE_BUFSIZE];
+#endif
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* All global variables used by this example are packed into a structure in
+ * order to avoid name collisions.
+ */
+
+extern struct composite_state_s g_composite;
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: composite_archinitialize
+ *
+ * Description:
+ * Perform architecture specific initialization.
+ *
+ ****************************************************************************/
+
+extern int composite_archinitialize(void);
+
+#endif /* __EXAMPLES_COMPOSITE_COMPOSITE_H */
diff --git a/apps/examples/composite/composite_main.c b/apps/examples/composite/composite_main.c
new file mode 100644
index 000000000..b965eacb7
--- /dev/null
+++ b/apps/examples/composite/composite_main.c
@@ -0,0 +1,851 @@
+/****************************************************************************
+ * examples/usbstorage/composite_main.c
+ *
+ * Copyright (C) 2012 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 <fcntl.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/usb/usbdev.h>
+#include <nuttx/usb/composite.h>
+#include <nuttx/usb/cdcacm.h>
+#include <nuttx/usb/usbmsc.h>
+#include <nuttx/usb/usbdev_trace.h>
+
+#include "composite.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* All global variables used by this example are packed into a structure in
+ * order to avoid name collisions.
+ */
+
+struct composite_state_s g_composite;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: show_memory_usage
+ ****************************************************************************/
+
+#ifdef CONFIG_EXAMPLES_COMPOSITE_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_COMPOSITE_DEBUGMM
+static void check_test_memory_usage(FAR const char *msg)
+{
+ /* Get the current memory usage */
+
+#ifdef CONFIG_CAN_PASS_STRUCTS
+ g_composite.mmcurrent = mallinfo();
+#else
+ (void)mallinfo(&g_composite.mmcurrent);
+#endif
+
+ /* Show the change from the previous time */
+
+ message("\%s:\n", msg);
+ show_memory_usage(&g_composite.mmprevious, &g_composite.mmcurrent);
+
+ /* Set up for the next test */
+
+#ifdef CONFIG_CAN_PASS_STRUCTS
+ g_composite.mmprevious = g_composite.mmcurrent;
+#else
+ memcpy(&g_composite.mmprevious, &g_composite.mmcurrent, sizeof(struct mallinfo));
+#endif
+}
+#else
+# define check_test_memory_usage(msg)
+#endif
+
+/****************************************************************************
+ * Name: check_test_memory_usage
+ ****************************************************************************/
+
+#ifdef CONFIG_EXAMPLES_COMPOSITE_DEBUGMM
+static void final_memory_usage(FAR const char *msg)
+{
+ /* Get the current memory usage */
+
+#ifdef CONFIG_CAN_PASS_STRUCTS
+ g_composite.mmcurrent = mallinfo();
+#else
+ (void)mallinfo(&g_composite.mmcurrent);
+#endif
+
+ /* Show the change from the previous time */
+
+ message("\n%s:\n", msg);
+ show_memory_usage(&g_composite.mmstart, &g_composite.mmcurrent);
+}
+#else
+# define final_memory_usage(msg)
+#endif
+
+/****************************************************************************
+ * Name: composite_enumerate
+ ****************************************************************************/
+
+#ifdef CONFIG_USBDEV_TRACE
+static int composite_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
+
+/****************************************************************************
+ * Name: dumptrace
+ *
+ * Description:
+ * Dump collected trace data.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBDEV_TRACE
+static int dumptrace(void)
+{
+ int ret;
+
+ ret = usbtrace_enumerate(composite_enumerate, NULL);
+ if (ret < 0)
+ {
+ message("dumptrace: usbtrace_enumerate failed: %d\n", -ret);
+ }
+ return ret;
+}
+#else
+# define dumptrace() (OK)
+#endif
+
+/****************************************************************************
+ * Name: open_serial
+ ****************************************************************************/
+
+#if !defined(CONFIG_NSH_BUILTIN_APPS) && !defined(CONFIG_DISABLE_SIGNALS)
+static int open_serial(void)
+{
+ int errcode;
+#ifdef CONFIG_USBDEV_TRACE
+ int ret;
+#endif
+
+ /* Open the USB serial device for writing (blocking) */
+
+ do
+ {
+ message("open_serial: Opening USB serial driver\n");
+ g_composite.outfd = open(CONFIG_EXAMPLES_COMPOSITE_SERDEV, O_WRONLY);
+ if (g_composite.outfd < 0)
+ {
+ errcode = errno;
+ message("open_serial: ERROR: Failed to open %s for writing: %d\n",
+ CONFIG_EXAMPLES_COMPOSITE_SERDEV, errcode);
+
+ /* ENOTCONN means that the USB device is not yet connected */
+
+ if (errcode == ENOTCONN)
+ {
+ message("open_serial: Not connected. Wait and try again.\n");
+ sleep(5);
+ }
+ else
+ {
+ /* Give up on other errors */
+
+ message("open_serial: Aborting\n");
+ return -errcode;
+ }
+ }
+
+ /* If USB tracing is enabled, then dump all collected trace data to
+ * stdout.
+ */
+
+#ifdef CONFIG_USBDEV_TRACE
+ ret = dumptrace();
+ if (ret < 0)
+ {
+ return ret;
+ }
+#endif
+ }
+ while (g_composite.outfd < 0);
+
+ /* Open the USB serial device for reading (non-blocking) */
+
+ g_composite.infd = open(CONFIG_EXAMPLES_COMPOSITE_SERDEV, O_RDONLY|O_NONBLOCK);
+ if (g_composite.infd < 0)
+ {
+ errcode = errno;
+ message("open_serial: ERROR: Failed to open%s for reading: %d\n",
+ CONFIG_EXAMPLES_COMPOSITE_SERDEV, errcode);
+ close(g_composite.outfd);
+ return -errcode;
+ }
+
+ message("open_serial: Successfully opened the serial driver\n");
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: echo_serial
+ ****************************************************************************/
+
+static int echo_serial(void)
+{
+ ssize_t bytesread;
+ ssize_t byteswritten;
+ int errcode;
+
+ /* Read data */
+
+ bytesread = read(g_composite.infd, g_composite.serbuf, CONFIG_EXAMPLES_COMPOSITE_BUFSIZE);
+ if (bytesread < 0)
+ {
+ errcode = errno;
+ if (errcode != EAGAIN)
+ {
+ message("echo_serial: ERROR: read failed: %d\n", errcode);
+ return -errcode;
+ }
+ return OK;
+ }
+
+ /* Echo data */
+
+ byteswritten = write(g_composite.outfd, g_composite.serbuf, bytesread);
+ if (byteswritten < 0)
+ {
+ errcode = errno;
+ message("echo_serial: ERROR: write failed: %d\n", errcode);
+ return -errcode;
+ }
+ else if (byteswritten != bytesread)
+ {
+ message("echo_serial: ERROR: read size: %d write size: %d\n",
+ bytesread, byteswritten);
+ }
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_mscclassobject
+ *
+ * Description:
+ * If the mass storage class driver is part of composite device, then
+ * its instantiation and configuration is a multi-step, board-specific,
+ * process (See comments for usbmsc_configure below). In this case,
+ * board-specific logic must provide board_mscclassobject().
+ *
+ * board_mscclassobject() is called from the composite driver. It must
+ * encapsulate the instantiation and configuration of the mass storage
+ * class and the return the mass storage device's class driver instance
+ * to the composite dirver.
+ *
+ * Input Parameters:
+ * classdev - The location to return the mass storage class' device
+ * instance.
+ *
+ * Returned Value:
+ * 0 on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int board_mscclassobject(FAR struct usbdevclass_driver_s **classdev)
+{
+ int ret;
+
+ DEBUGASSERT(g_composite.mschandle == NULL);
+
+ /* Initialize USB trace output IDs */
+
+ usbtrace_enable(TRACE_BITSET);
+ check_test_memory_usage("After usbtrace_enable()");
+
+ /* Configure the mass storage device */
+
+ message("board_mscclassobject: Configuring with NLUNS=%d\n", CONFIG_EXAMPLES_COMPOSITE_NLUNS);
+ ret = usbmsc_configure(CONFIG_EXAMPLES_COMPOSITE_NLUNS, &g_composite.mschandle);
+ if (ret < 0)
+ {
+ message("board_mscclassobject: usbmsc_configure failed: %d\n", -ret);
+ return ret;
+ }
+ message("board_mscclassobject: MSC handle=%p\n", g_composite.mschandle);
+ check_test_memory_usage("After usbmsc_configure()");
+
+ /* Bind the LUN(s) */
+
+ message("board_mscclassobject: Bind LUN=0 to %s\n", CONFIG_EXAMPLES_COMPOSITE_DEVPATH1);
+ ret = usbmsc_bindlun(g_composite.mschandle, CONFIG_EXAMPLES_COMPOSITE_DEVPATH1, 0, 0, 0, false);
+ if (ret < 0)
+ {
+ message("board_mscclassobject: usbmsc_bindlun failed for LUN 1 using %s: %d\n",
+ CONFIG_EXAMPLES_COMPOSITE_DEVPATH1, -ret);
+ usbmsc_uninitialize(g_composite.mschandle);
+ return ret;
+ }
+ check_test_memory_usage("After usbmsc_bindlun()");
+
+#if CONFIG_EXAMPLES_COMPOSITE_NLUNS > 1
+
+ message("board_mscclassobject: Bind LUN=1 to %s\n", CONFIG_EXAMPLES_COMPOSITE_DEVPATH2);
+ ret = usbmsc_bindlun(g_composite.mschandle, CONFIG_EXAMPLES_COMPOSITE_DEVPATH2, 1, 0, 0, false);
+ if (ret < 0)
+ {
+ message("board_mscclassobject: usbmsc_bindlun failed for LUN 2 using %s: %d\n",
+ CONFIG_EXAMPLES_COMPOSITE_DEVPATH2, -ret);
+ usbmsc_uninitialize(g_composite.mschandle);
+ return ret;
+ }
+ check_test_memory_usage("After usbmsc_bindlun() #2");
+
+#if CONFIG_EXAMPLES_COMPOSITE_NLUNS > 2
+
+ message("board_mscclassobject: Bind LUN=2 to %s\n", CONFIG_EXAMPLES_COMPOSITE_DEVPATH3);
+ ret = usbmsc_bindlun(g_composite.mschandle, CONFIG_EXAMPLES_COMPOSITE_DEVPATH3, 2, 0, 0, false);
+ if (ret < 0)
+ {
+ message("board_mscclassobject: usbmsc_bindlun failed for LUN 3 using %s: %d\n",
+ CONFIG_EXAMPLES_COMPOSITE_DEVPATH3, -ret);
+ usbmsc_uninitialize(g_composite.mschandle);
+ return ret;
+ }
+ check_test_memory_usage("After usbmsc_bindlun() #3");
+
+#endif
+#endif
+
+ /* Get the mass storage device's class object */
+
+ ret = usbmsc_classobject(g_composite.mschandle, classdev);
+ if (ret < 0)
+ {
+ message("board_mscclassobject: usbmsc_classobject failed: %d\n", -ret);
+ usbmsc_uninitialize(g_composite.mschandle);
+ }
+ check_test_memory_usage("After usbmsc_classobject()");
+ return ret;
+}
+
+/****************************************************************************
+ * Name: board_mscuninitialize
+ *
+ * Description:
+ * Un-initialize the USB storage class driver. This is just an application-
+ * specific wrapper aboutn usbmsc_unitialize() that is called form the composite
+ * device logic.
+ *
+ * Input Parameters:
+ * classdev - The class driver instrance previously give to the composite
+ * driver by board_mscclassobject().
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev)
+{
+ DEBUGASSERT(g_composite.mschandle != NULL &&
+ g_composite.mschandle == (FAR void *)classdev);
+ usbmsc_uninitialize(g_composite.mschandle);
+}
+
+/****************************************************************************
+ * Name: board_cdcclassobject
+ *
+ * Description:
+ * If the CDC serial class driver is part of composite device, then
+ * board-specific logic must provide board_cdcclassobject(). In the simplest
+ * case, board_cdcclassobject() is simply a wrapper around cdcacm_classobject()
+ * that provides the correct device minor number.
+ *
+ * Input Parameters:
+ * classdev - The location to return the CDC serial class' device
+ * instance.
+ *
+ * Returned Value:
+ * 0 on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int board_cdcclassobject(FAR struct usbdevclass_driver_s **classdev)
+{
+ int ret;
+
+ /* Initialize the USB serial driver */
+
+ message("board_cdcclassobject: Initializing USB serial driver\n");
+ ret = cdcacm_classobject(CONFIG_EXAMPLES_COMPOSITE_TTYUSB, classdev);
+ if (ret < 0)
+ {
+ message("board_cdcclassobject: ERROR: Failed to create the USB serial device: %d\n", -ret);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Name: board_cdcuninitialize
+ *
+ * Description:
+ * Un-initialize the USB serial class driver. This is just an application-
+ * specific wrapper aboutn cdcadm_unitialize() that is called form the composite
+ * device logic.
+ *
+ * Input Parameters:
+ * classdev - The class driver instrance previously give to the composite
+ * driver by board_cdcclassobject().
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void board_cdcuninitialize(FAR struct usbdevclass_driver_s *classdev)
+{
+ DEBUGASSERT(classdev != NULL);
+ cdcacm_uninitialize(classdev);
+}
+
+/****************************************************************************
+ * conn_main
+ *
+ * Description:
+ * This is the main program that configures the USB mass storage device
+ * and exports the LUN(s). If CONFIG_NSH_BUILTIN_APPS is defined
+ * in the NuttX configuration, then this program can be executed by
+ * entering the "msconn" command at the NSH console.
+ *
+ ****************************************************************************/
+
+int conn_main(int argc, char *argv[])
+{
+ 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_NSH_BUILTIN_APPS
+
+ /* Check if there is a non-NULL USB mass storage device handle (meaning that the
+ * USB mass storage device is already configured).
+ */
+
+ if (g_composite.cmphandle)
+ {
+ message("conn_main: ERROR: Already connected\n");
+ return 1;
+ }
+#endif
+
+#ifdef CONFIG_EXAMPLES_COMPOSITE_DEBUGMM
+# ifdef CONFIG_CAN_PASS_STRUCTS
+ g_composite.mmstart = mallinfo();
+ g_composite.mmprevious = g_composite.mmstart;
+# else
+ (void)mallinfo(&g_composite.mmstart);
+ memcpy(&g_composite.mmprevious, &g_composite.mmstart, sizeof(struct mallinfo));
+# endif
+#endif
+
+ /* Perform architecture-specific initialization */
+
+ message("conn_main: Performing architecture-specific intialization\n");
+ ret = composite_archinitialize();
+ if (ret < 0)
+ {
+ message("conn_main: composite_archinitialize failed: %d\n", -ret);
+ return 1;
+ }
+ check_test_memory_usage("After composite_archinitialize()");
+
+ /* Initialize the USB composite device device */
+
+ g_composite.cmphandle = composite_initialize();
+ if (!g_composite.cmphandle)
+ {
+ message("conn_main: composite_initialize failed\n");
+ return 1;
+ }
+ check_test_memory_usage("After composite_initialize()");
+
+#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);
+ ret = dumptrace();
+ if (ret < 0)
+ {
+ goto errout;
+ }
+#endif
+
+ /* 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_NSH_BUILTIN_APPS) && !defined(CONFIG_DISABLE_SIGNALS)
+
+ /* Otherwise, this thread will hang around and monitor the USB activity */
+
+ /* Open the serial driver */
+
+ ret = open_serial();
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ /* Now looping */
+
+ for (;;)
+ {
+ /* Sleep for a bit */
+
+ msgflush();
+ sleep(5);
+
+ /* Echo any serial data */
+
+ ret = echo_serial();
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ /* Dump trace data */
+
+# ifdef CONFIG_USBDEV_TRACE
+ message("\n" "conn_main: USB TRACE DATA:\n");
+ ret = dumptrace();
+ if (ret < 0)
+ {
+ goto errout;
+ }
+ check_test_memory_usage("After usbtrace_enumerate()");
+# else
+ message("conn_main: Still alive\n");
+# endif
+ }
+#else
+
+ message("conn_main: Connected\n");
+ check_test_memory_usage("After composite device connection");
+#endif
+
+ /* Dump debug memory usage */
+
+ message("conn_main: Exiting\n");
+#if !defined(CONFIG_NSH_BUILTIN_APPS) && !defined(CONFIG_DISABLE_SIGNALS)
+ close(g_composite.infd);
+ close(g_composite.outfd);
+#endif
+#ifdef CONFIG_NSH_BUILTIN_APPS
+#endif
+ final_memory_usage("Final memory usage");
+ return 0;
+
+errout:
+#if !defined(CONFIG_NSH_BUILTIN_APPS) && !defined(CONFIG_DISABLE_SIGNALS)
+ close(g_composite.infd);
+ close(g_composite.outfd);
+#endif
+ composite_uninitialize(g_composite.cmphandle);
+ final_memory_usage("Final memory usage");
+ return 1;
+}
+
+/****************************************************************************
+ * disconn_main
+ *
+ * Description:
+ * This is a program entry point that will disconnet the USB mass storage
+ * device. This program is only available if CONFIG_NSH_BUILTIN_APPS
+ * 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_NSH_BUILTIN_APPS
+int disconn_main(int argc, char *argv[])
+{
+ /* First check if the USB mass storage device is already connected */
+
+ if (!g_composite.cmphandle)
+ {
+ message("disconn_main: ERROR: Not connected\n");
+ return 1;
+ }
+ check_test_memory_usage("Since MS connection");
+
+ /* Then disconnect the device and uninitialize the USB mass storage driver */
+
+ composite_uninitialize(g_composite.cmphandle);
+ g_composite.mshandle = NULL;
+ message("disconn_main: Disconnected\n");
+ check_test_memory_usage("After composite_uninitialize()");
+
+ /* Dump debug memory usage */
+
+ final_memory_usage("Final memory usage");
+ return 0;
+}
+#endif
diff --git a/apps/examples/dhcpd/Kconfig b/apps/examples/dhcpd/Kconfig
new file mode 100644
index 000000000..10f513eca
--- /dev/null
+++ b/apps/examples/dhcpd/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_DHCPD
+ bool "DHCP server example"
+ default n
+ ---help---
+ Enable the DHCP server example
+
+if EXAMPLES_DHCPD
+endif
+
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..9c074f42b
--- /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 <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.
+#
+############################################################################
+
+# 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..9c554e8cd
--- /dev/null
+++ b/apps/examples/dhcpd/target.c
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * 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
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: dhcpd_main
+ ****************************************************************************/
+
+int dhcpd_main(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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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/discover/Kconfig b/apps/examples/discover/Kconfig
new file mode 100644
index 000000000..0a756d91d
--- /dev/null
+++ b/apps/examples/discover/Kconfig
@@ -0,0 +1,45 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLE_DISCOVER
+ bool "UDP Discovery Example"
+ default n
+ depends on NET_UDP
+ select NETUTILS_DISCOVER
+ ---help---
+ Enable the netutils/discover utility. This example initializes and
+ starts the UDP discover daemon. This daemon is useful for
+ discovering devices in local networks, especially with DHCP
+ configured devices. It listens for UDP broadcasts which also can
+ include a device class so that groups of devices can be discovered.
+ It is also possible to address all classes with a kind of broadcast
+ discover.
+
+config EXAMPLE_DISCOVER_DHCPC
+ bool "DHCP Client"
+ default n
+ depends on EXAMPLE_DISCOVER && !NSH_BUILTIN_APPS
+ select NETUTILS_DHCPC
+ select NETUTILS_RESOLV
+
+config EXAMPLE_DISCOVER_NOMAC
+ bool "Use Canned MAC Address"
+ default n
+ depends on EXAMPLE_DISCOVER && !NSH_BUILTIN_APPS
+
+config EXAMPLE_DISCOVER_IPADDR
+ hex "Target IP address"
+ default 0x0a000002
+ depends on EXAMPLE_DISCOVER && !NSH_BUILTIN_APPS && !EXAMPLE_DISCOVER_DHCPC
+
+config EXAMPLE_DISCOVER_DRIPADDR
+ hex "Default Router IP address (Gateway)"
+ default 0x0a000001
+ depends on EXAMPLE_DISCOVER && !NSH_BUILTIN_APPS
+
+config EXAMPLE_DISCOVER_NETMASK
+ hex "Network Mask"
+ default 0xffffff00
+ depends on EXAMPLE_DISCOVER && !NSH_BUILTIN_APPS
diff --git a/apps/examples/discover/Makefile b/apps/examples/discover/Makefile
new file mode 100644
index 000000000..3bb6b939e
--- /dev/null
+++ b/apps/examples/discover/Makefile
@@ -0,0 +1,106 @@
+############################################################################
+# apps/examples/discover/Makefile
+#
+# Copyright (C) 2012 Max Holtzberg. All rights reserved.
+# Copyright (C) 2008, 2010-2012 Gregory Nutt. All rights reserved.
+#
+# Authors: Max Holtzberg <mh@uvc.de>
+# 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
+
+# Discover built-in application info
+
+APPNAME = discover
+PRIORITY = SCHED_PRIORITY_DEFAULT
+STACKSIZE = 2048
+
+ASRCS =
+CSRCS = discover_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:
+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/discover/discover_main.c b/apps/examples/discover/discover_main.c
new file mode 100644
index 000000000..c3acb56df
--- /dev/null
+++ b/apps/examples/discover/discover_main.c
@@ -0,0 +1,188 @@
+/****************************************************************************
+ * examples/discover/discover_main.c
+ *
+ * Copyright (C) 2012 Max Holtzberg. All rights reserved.
+ * Copyright (C) 2008, 2011-2012 Gregory Nutt. All rights reserved.
+ *
+ * Authors: Max Holtzberg <mh@uvc.de>
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <debug.h>
+
+#include <net/if.h>
+#include <nuttx/net/uip/uip.h>
+#include <nuttx/net/uip/uip-arp.h>
+
+#include <apps/netutils/uiplib.h>
+#include <apps/netutils/discover.h>
+
+#ifdef CONFIG_EXAMPLE_DISCOVER_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_DISCOVER_DHCPC
+# include <apps/netutils/resolv.h>
+# include <apps/netutils/dhcpc.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * discover_main
+ ****************************************************************************/
+
+int discover_main(int argc, char *argv[])
+{
+ /* If this task is excecutated as an NSH built-in function, then the
+ * network has already been configured by NSH's start-up logic.
+ */
+
+#ifndef CONFIG_NSH_BUILTIN_APPS
+ struct in_addr addr;
+#if defined(CONFIG_EXAMPLE_DISCOVER_DHCPC) || defined(CONFIG_EXAMPLE_DISCOVER_NOMAC)
+ uint8_t mac[IFHWADDRLEN];
+#endif
+#ifdef CONFIG_EXAMPLE_DISCOVER_DHCPC
+ void *handle;
+#endif
+
+/* Many embedded network interfaces must have a software assigned MAC */
+
+#ifdef CONFIG_EXAMPLE_DISCOVER_NOMAC
+ mac[0] = 0x00;
+ mac[1] = 0xe0;
+ mac[2] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ uip_setmacaddr("eth0", mac);
+#endif
+
+ /* Set up our host address */
+
+#ifdef CONFIG_EXAMPLE_DISCOVER_DHCPC
+ addr.s_addr = 0;
+#else
+ addr.s_addr = HTONL(CONFIG_EXAMPLE_DISCOVER_IPADDR);
+#endif
+ uip_sethostaddr("eth0", &addr);
+
+ /* Set up the default router address */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLE_DISCOVER_DRIPADDR);
+ uip_setdraddr("eth0", &addr);
+
+ /* Setup the subnet mask */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLE_DISCOVER_NETMASK);
+ uip_setnetmask("eth0", &addr);
+
+#ifdef CONFIG_EXAMPLE_DISCOVER_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 /* CONFIG_EXAMPLE_DISCOVER_DHCPC */
+#endif /* CONFIG_NSH_BUILTIN_APPS */
+
+ if (discover_start() < 0)
+ {
+ ndbg("Could not start discover daemon.\n");
+ return ERROR;
+ }
+
+ return OK;
+}
+
diff --git a/apps/examples/ftpc/Kconfig b/apps/examples/ftpc/Kconfig
new file mode 100644
index 000000000..59fbbaa84
--- /dev/null
+++ b/apps/examples/ftpc/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_FTPC
+ bool "FTP client example"
+ default n
+ ---help---
+ Enable the FTP client example
+
+if EXAMPLES_FTPC
+endif
diff --git a/apps/examples/ftpc/Makefile b/apps/examples/ftpc/Makefile
new file mode 100644
index 000000000..cf32be0f0
--- /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 <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
+
+# 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..429976ad0
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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 100644
index 000000000..df05f45d2
--- /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 <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 <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 100644
index 000000000..866a69cdb
--- /dev/null
+++ b/apps/examples/ftpc/ftpc_main.c
@@ -0,0 +1,455 @@
+/****************************************************************************
+ * examples/ftpc/ftpc_main.c
+ *
+ * Copyright (C) 2011-2012 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+#include <apps/ftpc.h>
+
+#include <apps/readline.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+1];
+ 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;
+#ifndef CONFIG_EXAMPLES_FTPC_FGETS
+ int ret;
+#endif
+
+ 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 */
+
+#ifdef CONFIG_EXAMPLES_FTPC_FGETS
+ /* fgets returns NULL on end-of-file or any I/O error */
+
+ if (fgets(g_line, CONFIG_FTPC_LINELEN, stdin) == NULL)
+ {
+ printf("ERROR: fgets failed: %d\n", errno);
+ return 1;
+ }
+#else
+ ret = readline(g_line, CONFIG_FTPC_LINELEN, stdin, stdout);
+
+ /* Readline normally returns the number of characters read,
+ * but will return 0 on end of file or a negative value
+ * if an error occurs. Either will cause the session to
+ * terminate.
+ */
+
+ if (ret <= 0)
+ {
+ printf("ERROR: readline failed: %d\n", ret);
+ return 1;
+ }
+#endif
+ else
+ {
+ /* Parse and process the command */
+
+ (void)ftpc_parse(handle, g_line);
+ FFLUSH();
+ }
+ }
+
+ return 0;
+}
diff --git a/apps/examples/ftpd/Kconfig b/apps/examples/ftpd/Kconfig
new file mode 100644
index 000000000..5b2a2f95f
--- /dev/null
+++ b/apps/examples/ftpd/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_FTPD
+ bool "FTP server example"
+ default n
+ ---help---
+ Enable the FTP server example
+
+if EXAMPLES_FTPD
+endif
diff --git a/apps/examples/ftpd/Makefile b/apps/examples/ftpd/Makefile
new file mode 100644
index 000000000..4eb25c9e9
--- /dev/null
+++ b/apps/examples/ftpd/Makefile
@@ -0,0 +1,101 @@
+############################################################################
+# apps/examples/ftpd/Makefile
+#
+# Copyright (C) 2012 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
+
+# Hello, World! Example
+
+ASRCS =
+CSRCS = ftpd_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: 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,ftpd_start,SCHED_PRIORITY_DEFAULT,2048,ftpd_start)
+ $(call REGISTER,ftpd_stop,SCHED_PRIORITY_DEFAULT,2048,ftpd_stop)
+ @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/ftpd/ftpd.h b/apps/examples/ftpd/ftpd.h
new file mode 100644
index 000000000..6a439e818
--- /dev/null
+++ b/apps/examples/ftpd/ftpd.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+ * apps/examples/ftpd/ftpd.h
+ * Interface for the Contiki ftpd.
+ *
+ * Copyright (C) 2012 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. 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_EXAMPLES_FTPD_FTPD_H
+#define __APPS_EXAMPLES_FTPD_FTPD_H
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* CONFIG_EXAMPLES_FTPD_PRIO - Priority of the FTP daemon.
+ * Default: SCHED_PRIORITY_DEFAULT
+ * CONFIG_EXAMPLES_FTPD_STACKSIZE - Stack size allocated for the
+ * FTP daemon. Default: 2048
+ * CONFIG_EXAMPLES_FTPD_NONETINIT - Define to suppress configuration of the
+ * network by apps/examples/ftpd. You would need to suppress network
+ * configuration if the network is configuration prior to running the
+ * example.
+ *
+ * If CONFIG_EXAMPLES_FTPD_NONETINIT is not defined, then the following may
+ * be specified to customized the network configuration:
+ *
+ * CONFIG_EXAMPLE_FTPD_NOMAC - If the hardware has no MAC address of its
+ * own, define this =y to provide a bogus address for testing.
+ * CONFIG_EXAMPLE_FTPD_IPADDR - The target IP address. Default 10.0.0.2
+ * CONFIG_EXAMPLE_FTPD_DRIPADDR - The default router address. Default
+ * 10.0.0.1
+ * CONFIG_EXAMPLE_FTPD_NETMASK - The network mask. Default: 255.255.255.0
+ */
+
+#ifndef CONFIG_EXAMPLES_FTPD_PRIO
+# define CONFIG_EXAMPLES_FTPD_PRIO SCHED_PRIORITY_DEFAULT
+#endif
+
+#ifndef CONFIG_EXAMPLES_FTPD_STACKSIZE
+# define CONFIG_EXAMPLES_FTPD_STACKSIZE 2048
+#endif
+
+#ifndef CONFIG_EXAMPLES_FTPD_CLIENTPRIO
+# define CONFIG_EXAMPLES_FTPD_CLIENTPRIO SCHED_PRIORITY_DEFAULT
+#endif
+
+#ifndef CONFIG_EXAMPLES_FTPD_CLIENTSTACKSIZE
+# define CONFIG_EXAMPLES_FTPD_CLIENTSTACKSIZE 2048
+#endif
+
+/* NSH always initializes the network */
+
+#if defined(CONFIG_NSH_BUILTIN_APPS) && !defined(CONFIG_EXAMPLES_FTPD_NONETINIT)
+# define CONFIG_EXAMPLES_FTPD_NONETINIT 1
+#endif
+
+#ifdef CONFIG_EXAMPLES_FTPD_NONETINIT
+# undef CONFIG_EXAMPLE_FTPD_IPADDR
+# undef CONFIG_EXAMPLE_FTPD_DRIPADDR
+# undef CONFIG_EXAMPLE_FTPD_NETMASK
+#else
+# ifndef CONFIG_EXAMPLE_FTPD_IPADDR
+# define CONFIG_EXAMPLE_FTPD_IPADDR 0x0a000002
+# endif
+# ifndef CONFIG_EXAMPLE_FTPD_DRIPADDR
+# define CONFIG_EXAMPLE_FTPD_DRIPADDR 0x0a000001
+# endif
+# ifndef CONFIG_EXAMPLE_FTPD_NETMASK
+# define CONFIG_EXAMPLE_FTPD_NETMASK 0xffffff00
+# endif
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* This structure describes one entry in a table of accounts */
+
+struct fptd_account_s
+{
+ uint8_t flags;
+ FAR const char *user;
+ FAR const char *password;
+ FAR const char *home;
+};
+
+/* To minimize the probability of name collisitions, all FTPD example
+ * global data is maintained in single structure.
+ */
+
+struct ftpd_globals_s
+{
+ bool initialized; /* True: Networking is initialized. The
+ * network must be initialized only once.
+ */
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ volatile bool stop; /* True: Request daemon to exit */
+ volatile bool running; /* True: The daemon is running */
+#endif
+ pid_t pid; /* Task ID of the FTPD daemon. The value
+ * -1 is a redundant indication that the
+ * daemon is not running.
+ */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* To minimize the probability of name collisitions, all FTPD example
+ * global data is maintained in a single instance of a structure.
+ */
+
+extern struct ftpd_globals_s g_ftpdglob;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#endif /* __APPS_EXAMPLES_FTPD_FTPD_H */
diff --git a/apps/examples/ftpd/ftpd_main.c b/apps/examples/ftpd/ftpd_main.c
new file mode 100644
index 000000000..6d19f952c
--- /dev/null
+++ b/apps/examples/ftpd/ftpd_main.c
@@ -0,0 +1,292 @@
+/****************************************************************************
+ * examples/telnetd/shell.c
+ *
+ * Copyright (C) 2012 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 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sched.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <netinet/in.h>
+
+#include <apps/netutils/uiplib.h>
+#include <apps/netutils/ftpd.h>
+
+#include "ftpd.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct fptd_account_s g_ftpdaccounts[] =
+{
+ { FTPD_ACCOUNTFLAG_SYSTEM, "root", "abc123", NULL },
+ { FTPD_ACCOUNTFLAG_GUEST, "ftp", NULL, NULL },
+ { FTPD_ACCOUNTFLAG_GUEST, "anonymous", NULL, NULL },
+};
+#define NACCOUNTS (sizeof(g_ftpdaccounts) / sizeof(struct fptd_account_s))
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* To minimize the probability of name collisitions, all FTPD example
+ * global data is maintained in a single instance of a structure.
+ */
+
+struct ftpd_globals_s g_ftpdglob;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: fptd_netinit
+ ****************************************************************************/
+
+static void fptd_netinit(void)
+{
+#ifndef CONFIG_EXAMPLES_FTPD_NONETINIT
+ struct in_addr addr;
+#ifdef CONFIG_EXAMPLE_FTPD_NOMAC
+ uint8_t mac[IFHWADDRLEN];
+#endif
+
+/* Many embedded network interfaces must have a software assigned MAC */
+
+#ifdef CONFIG_EXAMPLE_FTPD_NOMAC
+ mac[0] = 0x00;
+ mac[1] = 0xe0;
+ mac[2] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ uip_setmacaddr("eth0", mac);
+#endif
+
+ /* Set up our host address */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLE_FTPD_IPADDR);
+ uip_sethostaddr("eth0", &addr);
+
+ /* Set up the default router address */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLE_FTPD_DRIPADDR);
+ uip_setdraddr("eth0", &addr);
+
+ /* Setup the subnet mask */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLE_FTPD_NETMASK);
+ uip_setnetmask("eth0", &addr);
+#endif /* CONFIG_EXAMPLES_FTPD_NONETINIT */
+}
+
+/****************************************************************************
+ * Name: ftpd_accounts
+ ****************************************************************************/
+
+static void ftpd_accounts(FTPD_SESSION handle)
+{
+ FAR const struct fptd_account_s *account;
+ int i;
+
+ printf("Adding accounts:\n");
+ for (i = 0; i < NACCOUNTS; i++)
+ {
+ account = &g_ftpdaccounts[i];
+
+ printf("%d. %s account: USER=%s PASSWORD=%s HOME=%s\n", i+1,
+ (account->flags & FTPD_ACCOUNTFLAG_SYSTEM) != 0 ? "Root" : "User",
+ (!account->user) ? "(none)" : account->user,
+ (!account->password) ? "(none)" : account->password,
+ (!account->home) ? "(none)" : account->home);
+
+ ftpd_adduser(handle, account->flags, account->user,
+ account->password, account->home);
+ }
+}
+
+/****************************************************************************
+ * Name: ftpd_daemon
+ ****************************************************************************/
+
+int ftpd_daemon(int s_argc, char **s_argv)
+{
+ FTPD_SESSION handle;
+ int ret;
+
+ /* The FTPD daemon has been started */
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ g_ftpdglob.running = true;
+#endif
+ printf("FTP daemon [%d] started\n", g_ftpdglob.pid);
+
+ /* Open FTPD */
+
+ handle = ftpd_open();
+ if (!handle)
+ {
+ printf("FTP daemon [%d] failed to open FTPD\n", g_ftpdglob.pid);
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ g_ftpdglob.running = false;
+ g_ftpdglob.stop = false;
+#endif
+ g_ftpdglob.pid = -1;
+ return EXIT_FAILURE;
+ }
+
+ /* Configure acounts */
+
+ (void)ftpd_accounts(handle);
+
+ /* Then drive the FTPD server. */
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ while (g_ftpdglob.stop == 0)
+#else
+ for (;;)
+#endif
+ {
+ /* If ftpd_session returns success, it means that a new FTP session
+ * has been started.
+ */
+
+ ret = ftpd_session(handle, 5000);
+
+ /* If any interesting happened (i.e., any thing other than a timeout),
+ * then report the interesting event.
+ */
+
+ if (ret != -ETIMEDOUT)
+ {
+ printf("FTP daemon [%d] ftpd_session returned %d\n", g_ftpdglob.pid, ret);
+ }
+ }
+
+ /* Close the FTPD server and exit (we can get here only if
+ * CONFIG_NSH_BUILTIN_APPS is defined).
+ */
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ printf("FTP daemon [%d] stopping\n", g_ftpdglob.pid);
+ g_ftpdglob.running = false;
+ g_ftpdglob.stop = false;
+ g_ftpdglob.pid = -1;
+ ftpd_close(handle);
+#endif
+ return EXIT_SUCCESS;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: ftpd_main
+ ****************************************************************************/
+
+int ftpd_main(int s_argc, char **s_argv)
+{
+ /* Check if we have already initialized the network */
+
+ if (!g_ftpdglob.initialized)
+ {
+
+ /* Bring up the network */
+
+ printf("Initializing the network\n");
+ fptd_netinit();
+
+ /* Initialize daemon state */
+
+ g_ftpdglob.initialized = true;
+ g_ftpdglob.pid = -1;
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ g_ftpdglob.stop = false;
+ g_ftpdglob.running = false;
+#endif
+ }
+
+ /* Then start the new daemon (if it is not already running) */
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ if (g_ftpdglob.stop && g_ftpdglob.running)
+ {
+ printf("Waiting for FTP daemon [%d] to stop\n", g_ftpdglob.pid);
+ return EXIT_FAILURE;
+ }
+ else
+#endif
+ if (!g_ftpdglob.running)
+ {
+ printf("Starting the FTP daemon\n");
+ g_ftpdglob.pid = TASK_CREATE("FTP daemon", CONFIG_EXAMPLES_FTPD_PRIO,
+ CONFIG_EXAMPLES_FTPD_STACKSIZE,
+ ftpd_daemon, NULL);
+ if (g_ftpdglob.pid < 0)
+ {
+ printf("Failed to start the FTP daemon: %d\n", errno);
+ return EXIT_FAILURE;
+ }
+ }
+ else
+ {
+ printf("FTP daemon [%d] is running\n", g_ftpdglob.pid);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/****************************************************************************
+ * Name: ftpd_stop
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+int ftpd_stop(int s_argc, char **s_argv)
+{
+ if (!g_ftpdglob.initialized || !g_ftpdglob.running)
+ {
+ printf("The FTP daemon not running\n");
+ return EXIT_FAILURE;
+ }
+
+ printf("Stopping the FTP daemon, pid=%d\n", g_ftpdglob.pid);
+ g_ftpdglob.stop = true;
+ return EXIT_SUCCESS;
+}
+#endif
diff --git a/apps/examples/hello/Kconfig b/apps/examples/hello/Kconfig
new file mode 100644
index 000000000..d697daa8a
--- /dev/null
+++ b/apps/examples/hello/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_HELLO
+ bool "\"Hello, World!\" example"
+ default n
+ ---help---
+ Enable the \"Hello, World!\" example
+
+if EXAMPLES_HELLO
+endif
diff --git a/apps/examples/hello/Makefile b/apps/examples/hello/Makefile
new file mode 100644
index 000000000..1d78d723e
--- /dev/null
+++ b/apps/examples/hello/Makefile
@@ -0,0 +1,105 @@
+############################################################################
+# apps/examples/hello/Makefile
+#
+# Copyright (C) 2008, 2010-2012 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
+
+# Hello, World! built-in application info
+
+APPNAME = hello
+PRIORITY = SCHED_PRIORITY_DEFAULT
+STACKSIZE = 2048
+
+# Hello, World! Example
+
+ASRCS =
+CSRCS = hello_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:
+ifeq ($(CONFIG_EXAMPLES_HELLO_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/hello/hello_main.c b/apps/examples/hello/hello_main.c
new file mode 100644
index 000000000..229027c36
--- /dev/null
+++ b/apps/examples/hello/hello_main.c
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * examples/hello/hello_main.c
+ *
+ * Copyright (C) 2008, 2011-2012 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 <stdio.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * hello_main
+ ****************************************************************************/
+
+int hello_main(int argc, char *argv[])
+{
+ printf("Hello, World!!\n");
+ return 0;
+}
+
diff --git a/apps/examples/helloxx/Kconfig b/apps/examples/helloxx/Kconfig
new file mode 100644
index 000000000..336389d24
--- /dev/null
+++ b/apps/examples/helloxx/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_HELLOXX
+ bool "\"Hello, World!\" C++ example"
+ default n
+ ---help---
+ Enable the \"Hello, World!\" C++ example
+
+if EXAMPLES_HELLOXX
+endif
diff --git a/apps/examples/helloxx/Makefile b/apps/examples/helloxx/Makefile
new file mode 100644
index 000000000..8e85eab23
--- /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 <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
+
+# Hello, World! C++ Example
+
+ASRCS =
+CSRCS =
+CXXSRCS = helloxx_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/helloxx_main.cxx b/apps/examples/helloxx/helloxx_main.cxx
new file mode 100644
index 000000000..60fd0487b
--- /dev/null
+++ b/apps/examples/helloxx/helloxx_main.cxx
@@ -0,0 +1,165 @@
+//***************************************************************************
+// examples/helloxx/helloxx_main.cxx
+//
+// Copyright (C) 2009, 2011-2012 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 <cstdio>
+#include <debug.h>
+
+#include <nuttx/init.h>
+#include <nuttx/arch.h>
+
+//***************************************************************************
+// Definitions
+//***************************************************************************
+// Debug ********************************************************************
+// Non-standard debug that may be enabled just for testing the constructors
+
+#ifndef CONFIG_DEBUG
+# undef CONFIG_DEBUG_CXX
+#endif
+
+#ifdef CONFIG_DEBUG_CXX
+# define cxxdbg dbg
+# define cxxlldbg lldbg
+# ifdef CONFIG_DEBUG_VERBOSE
+# define cxxvdbg vdbg
+# define cxxllvdbg llvdbg
+# else
+# define cxxvdbg(x...)
+# define cxxllvdbg(x...)
+# endif
+#else
+# define cxxdbg(x...)
+# define cxxlldbg(x...)
+# define cxxvdbg(x...)
+# define cxxllvdbg(x...)
+#endif
+
+//***************************************************************************
+// Private Classes
+//***************************************************************************
+
+class CHelloWorld
+{
+ public:
+ CHelloWorld(void) : mSecret(42)
+ {
+ cxxdbg("Constructor: mSecret=%d\n", mSecret);
+ }
+
+ ~CHelloWorld(void)
+ {
+ cxxdbg("Destructor\n");
+ }
+
+ bool HelloWorld(void)
+ {
+ cxxdbg("HelloWorld: mSecret=%d\n", mSecret);
+
+ 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
+//***************************************************************************
+
+// Define a statically constructed CHellowWorld instance if C++ static
+// initializers are supported by the platform
+
+#ifdef CONFIG_HAVE_CXXINITIALIZE
+static CHelloWorld g_HelloWorld;
+#endif
+
+//***************************************************************************
+// Public Functions
+//***************************************************************************
+
+/****************************************************************************
+ * Name: helloxx_main
+ ****************************************************************************/
+
+int helloxx_main(int argc, char *argv[])
+{
+ // If C++ initialization for static constructors is supported, then do
+ // that first
+
+#ifdef CONFIG_HAVE_CXXINITIALIZE
+ up_cxxinitialize();
+#endif
+
+ // Exercise an explictly instantiated C++ object
+
+ CHelloWorld *pHelloWorld = new CHelloWorld;
+ printf("helloxx_main: Saying hello from the dynamically constructed instance\n");
+ pHelloWorld->HelloWorld();
+
+ // Exercise an C++ object instantiated on the stack
+
+#ifndef CONFIG_EXAMPLES_HELLOXX_NOSTACKCONST
+ CHelloWorld HelloWorld;
+
+ printf("helloxx_main: Saying hello from the instance constructed on the stack\n");
+ HelloWorld.HelloWorld();
+#endif
+
+ // Exercise an statically constructed C++ object
+
+#ifdef CONFIG_HAVE_CXXINITIALIZE
+ printf("helloxx_main: Saying hello from the statically constructed instance\n");
+ g_HelloWorld.HelloWorld();
+#endif
+
+ delete pHelloWorld;
+ return 0;
+}
+
diff --git a/apps/examples/hidkbd/Kconfig b/apps/examples/hidkbd/Kconfig
new file mode 100644
index 000000000..503d9d9d9
--- /dev/null
+++ b/apps/examples/hidkbd/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_HIDKBD
+ bool "USB HID keyboard example"
+ default n
+ ---help---
+ Enable the USB HID keyboard example
+
+if EXAMPLES_HIDKBD
+endif
diff --git a/apps/examples/hidkbd/Makefile b/apps/examples/hidkbd/Makefile
new file mode 100644
index 000000000..8dccb0475
--- /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 <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
+
+# 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..e744a495c
--- /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 <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 <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: hidkbd_main
+ ****************************************************************************/
+
+int hidkbd_main(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("hidkbd_main: Register class drivers\n");
+ ret = usbhost_kbdinit();
+ if (ret != OK)
+ {
+ printf("hidkbd_main: Failed to register the KBD class\n");
+ }
+
+ /* Then get an instance of the USB host interface */
+
+ printf("hidkbd_main: Initialize USB host keyboard driver\n");
+ g_drvr = usbhost_initialize(0);
+ if (g_drvr)
+ {
+ /* Start a thread to handle device connection. */
+
+ printf("hidkbd_main: 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/Kconfig b/apps/examples/igmp/Kconfig
new file mode 100644
index 000000000..d94121376
--- /dev/null
+++ b/apps/examples/igmp/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_IGMP
+ bool "IGMP example"
+ default n
+ ---help---
+ Enable the IGMP example
+
+if EXAMPLES_IGMP
+endif
diff --git a/apps/examples/igmp/Makefile b/apps/examples/igmp/Makefile
new file mode 100644
index 000000000..1bab2c62e
--- /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 <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
+
+# 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 100644
index 000000000..73ca8a3e6
--- /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 <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 <unistd.h>
+#include <debug.h>
+
+#include <net/if.h>
+#include <nuttx/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
+ ****************************************************************************/
+
+/****************************************************************************
+ * igmp_main
+ ****************************************************************************/
+
+int igmp_main(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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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 100644
index 000000000..093f58c1f
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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/Kconfig b/apps/examples/lcdrw/Kconfig
new file mode 100644
index 000000000..2308ddc60
--- /dev/null
+++ b/apps/examples/lcdrw/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_LCDRW
+ bool "LCD read/write example"
+ default n
+ ---help---
+ Enable the LCD read/write example
+
+if EXAMPLES_LCDRW
+endif
diff --git a/apps/examples/lcdrw/Makefile b/apps/examples/lcdrw/Makefile
new file mode 100644
index 000000000..cc23d3fe1
--- /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 <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
+
+# 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..0852502f3
--- /dev/null
+++ b/apps/examples/lcdrw/lcdrw_main.c
@@ -0,0 +1,253 @@
+/****************************************************************************
+ * examples/lcdrw/lcdrw_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 <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
+ ****************************************************************************/
+
+int lcdrw_main(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);
+ }
+
+ /* Loop, writing all possible values to the LCD */
+
+ 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. */
+
+ 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/Kconfig b/apps/examples/mm/Kconfig
new file mode 100644
index 000000000..81ce4c453
--- /dev/null
+++ b/apps/examples/mm/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_MM
+ bool "Memory management example"
+ default n
+ ---help---
+ Enable the memory management example
+
+if EXAMPLES_MM
+endif
diff --git a/apps/examples/mm/Makefile b/apps/examples/mm/Makefile
new file mode 100644
index 000000000..24ed4926f
--- /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 <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
+
+# 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..149550418
--- /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 <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 <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: mm_main
+ ****************************************************************************/
+
+int mm_main(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/modbus/Kconfig b/apps/examples/modbus/Kconfig
new file mode 100644
index 000000000..4519ed2e3
--- /dev/null
+++ b/apps/examples/modbus/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_MODBUS
+ bool "FreeModBus example"
+ default n
+ ---help---
+ Enable the FreeModBus example
+
+if EXAMPLES_MODBUS
+endif
diff --git a/apps/examples/modbus/Makefile b/apps/examples/modbus/Makefile
new file mode 100644
index 000000000..6dbc7e424
--- /dev/null
+++ b/apps/examples/modbus/Makefile
@@ -0,0 +1,105 @@
+############################################################################
+# apps/examples/modbus/Makefile
+#
+# Copyright (C) 2012 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
+
+# FreeModBus demo built-in application info
+
+APPNAME = modbus
+PRIORITY = SCHED_PRIORITY_DEFAULT
+STACKSIZE = 2048
+
+# FreeModBus demo
+
+ASRCS =
+CSRCS = modbus_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:
+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/modbus/modbus_main.c b/apps/examples/modbus/modbus_main.c
new file mode 100644
index 000000000..13967f6fd
--- /dev/null
+++ b/apps/examples/modbus/modbus_main.c
@@ -0,0 +1,550 @@
+/****************************************************************************
+ * examples/modbus/main.c
+ *
+ * Copyright (C) 2012 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.
+ *
+ ****************************************************************************
+ * Leveraged from:
+ *
+ * FreeModbus Libary: Linux Demo Application
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <termios.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbport.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_EXAMPLES_MODBUS_PORT
+# define CONFIG_EXAMPLES_MODBUS_PORT 0
+#endif
+
+#ifndef CONFIG_EXAMPLES_MODBUS_BAUD
+# define CONFIG_EXAMPLES_MODBUS_BAUD B38400
+#endif
+
+#ifndef CONFIG_EXAMPLES_MODBUS_PARITY
+# define CONFIG_EXAMPLES_MODBUS_PARITY MB_PAR_EVEN
+#endif
+
+#ifndef CONFIG_EXAMPLES_MODBUS_REG_INPUT_START
+# define CONFIG_EXAMPLES_MODBUS_REG_INPUT_START 1000
+#endif
+
+#ifndef CONFIG_EXAMPLES_MODBUS_REG_INPUT_NREGS
+# define CONFIG_EXAMPLES_MODBUS_REG_INPUT_NREGS 4
+#endif
+
+#ifndef CONFIG_EXAMPLES_MODBUS_REG_HOLDING_START
+# define CONFIG_EXAMPLES_MODBUS_REG_HOLDING_START 2000
+#endif
+
+#ifndef CONFIG_EXAMPLES_MODBUS_REG_HOLDING_NREGS
+# define CONFIG_EXAMPLES_MODBUS_REG_HOLDING_NREGS 130
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum modbus_threadstate_e
+{
+ STOPPED = 0,
+ RUNNING,
+ SHUTDOWN
+};
+
+struct modbus_state_s
+{
+ enum modbus_threadstate_e threadstate;
+ uint16_t reginput[CONFIG_EXAMPLES_MODBUS_REG_INPUT_NREGS];
+ uint16_t regholding[CONFIG_EXAMPLES_MODBUS_REG_HOLDING_NREGS];
+ pthread_t threadid;
+ pthread_mutex_t lock;
+ volatile bool quit;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline int modbus_initialize(void);
+static void *modbus_pollthread(void *pvarg);
+static inline int modbus_create_pollthread(void);
+static void modbus_showusage(FAR const char *progname, int exitcode);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct modbus_state_s g_modbus;
+static const uint8_t g_slaveid[] = { 0xaa, 0xbb, 0xcc };
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: modbus_initialize
+ *
+ * Description:
+ * Called from the ModBus polling thread in order to initialized the
+ * FreeModBus interface.
+ *
+ ****************************************************************************/
+
+static inline int modbus_initialize(void)
+{
+ eMBErrorCode mberr;
+ int status;
+
+ /* Verify that we are in the stopped state */
+
+ if (g_modbus.threadstate != STOPPED)
+ {
+ fprintf(stderr, "modbus_main: "
+ "ERROR: Bad state: %d\n", g_modbus.threadstate);
+ return EINVAL;
+ }
+
+ /* Initialize the ModBus demo data structures */
+
+ status = pthread_mutex_init(&g_modbus.lock, NULL);
+ if (status != 0)
+ {
+ fprintf(stderr, "modbus_main: "
+ "ERROR: pthread_mutex_init failed: %d\n", status);
+ return status;
+ }
+
+ status = ENODEV;
+
+ /* Initialize the FreeModBus library.
+ *
+ * MB_RTU = RTU mode
+ * 0x0a = Slave address
+ * CONFIG_EXAMPLES_MODBUS_PORT = port, default=0 (i.e., /dev/ttyS0)
+ * CONFIG_EXAMPLES_MODBUS_BAUD = baud, default=B38400
+ * CONFIG_EXAMPLES_MODBUS_PARITY = parity, default=MB_PAR_EVEN
+ */
+
+ mberr = eMBInit(MB_RTU, 0x0a, CONFIG_EXAMPLES_MODBUS_PORT,
+ CONFIG_EXAMPLES_MODBUS_BAUD, CONFIG_EXAMPLES_MODBUS_PARITY);
+ if (mberr != MB_ENOERR)
+ {
+ fprintf(stderr, "modbus_main: "
+ "ERROR: eMBInit failed: %d\n", mberr);
+ goto errout_with_mutex;
+ }
+
+ /* Set the slave ID
+ *
+ * 0x34 = Slave ID
+ * true = Is running (run indicator status = 0xff)
+ * g_slaveid = Additional values to be returned with the slave ID
+ * 3 = Length of additional values (in bytes)
+ */
+
+ mberr = eMBSetSlaveID(0x34, true, g_slaveid, 3);
+ if (mberr != MB_ENOERR)
+ {
+ fprintf(stderr, "modbus_main: "
+ "ERROR: eMBSetSlaveID failed: %d\n", mberr);
+ goto errout_with_modbus;
+ }
+
+ /* Enable FreeModBus */
+
+ mberr = eMBEnable();
+ if (mberr == MB_ENOERR)
+ {
+ fprintf(stderr, "modbus_main: "
+ "ERROR: eMBEnable failed: %d\n", mberr);
+ goto errout_with_modbus;
+ }
+
+ /* Successfully initialized */
+
+ g_modbus.threadstate = RUNNING;
+ return OK;
+
+errout_with_modbus:
+ /* Release hardware resources. */
+
+ (void)eMBClose();
+
+errout_with_mutex:
+
+ /* Free/uninitialize data structures */
+
+ (void)pthread_mutex_destroy(&g_modbus.lock);
+
+ g_modbus.threadstate = STOPPED;
+ return status;
+}
+
+/****************************************************************************
+ * Name: modbus_pollthread
+ *
+ * Description:
+ * This is the ModBus polling thread.
+ *
+ ****************************************************************************/
+
+static void *modbus_pollthread(void *pvarg)
+{
+ eMBErrorCode mberr;
+ int ret;
+
+ /* Initialize the modbus */
+
+ ret = modbus_initialize();
+ if (ret != OK)
+ {
+ fprintf(stderr, "modbus_main: "
+ "ERROR: modbus_initialize failed: %d\n", ret);
+ return NULL;
+ }
+
+ /* Then loop until we are commanded to shutdown */
+
+ do
+ {
+ /* Poll */
+
+ mberr = eMBPoll();
+ if (mberr != MB_ENOERR)
+ {
+ break;
+ }
+
+ /* Generate some random input */
+
+ g_modbus.reginput[0] = (uint16_t)rand();
+ }
+ while (g_modbus.threadstate != SHUTDOWN);
+
+ /* Disable */
+
+ (void)eMBDisable();
+
+ /* Release hardware resources. */
+
+ (void)eMBClose();
+
+ /* Free/uninitialize data structures */
+
+ (void)pthread_mutex_destroy(&g_modbus.lock);
+ g_modbus.threadstate = STOPPED;
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: modbus_create_pollthread
+ *
+ * Description:
+ * Start the ModBus polling thread
+ *
+ ****************************************************************************/
+
+static inline int modbus_create_pollthread(void)
+{
+ int ret;
+
+ if (g_modbus.threadstate == STOPPED)
+ {
+ ret = pthread_create(&g_modbus.threadid, NULL, modbus_pollthread, NULL);
+ }
+ else
+ {
+ ret = EINVAL;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: modbus_showusage
+ *
+ * Description:
+ * Show usage of the demo program and exit
+ *
+ ****************************************************************************/
+
+static void modbus_showusage(FAR const char *progname, int exitcode)
+{
+ printf("USAGE: %s [-d|e|s|q|h]\n\n", progname);
+ printf("Where:\n");
+ printf(" -d : Disable protocol stack\n");
+ printf(" -e : Enable the protocol stack\n");
+ printf(" -s : Show current status\n");
+ printf(" -q : Quit application\n");
+ printf(" -h : Show this information\n");
+ printf("\n");
+ exit(exitcode);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: modbus_main
+ *
+ * Description:
+ * This is the main entry point to the demo program
+ *
+ ****************************************************************************/
+
+int modbus_main(int argc, char *argv[])
+{
+ int option;
+ int ret;
+
+ /* Handle command line arguments */
+
+ g_modbus.quit = false;
+
+ while ((option = getopt(argc, argv, "desqh")) != ERROR)
+ {
+ switch (option)
+ {
+ case 'd': /* Disable protocol stack */
+ (void)pthread_mutex_lock(&g_modbus.lock);
+ g_modbus.threadstate = SHUTDOWN;
+ (void)pthread_mutex_unlock(&g_modbus.lock);
+ break;
+
+ case 'e': /* Enable the protocol stack */
+ {
+ ret = modbus_create_pollthread();
+ if (ret != OK)
+ {
+ fprintf(stderr, "modbus_main: "
+ "ERROR: modbus_create_pollthread failed: %d\n", ret);
+ exit(EXIT_FAILURE);
+ }
+ }
+ break;
+
+ case 's': /* Show current status */
+ switch (g_modbus.threadstate)
+ {
+ case RUNNING:
+ printf("modbus_main: Protocol stack is running\n");
+ break;
+
+ case STOPPED:
+ printf("modbus_main: Protocol stack is stopped\n");
+ break;
+
+ case SHUTDOWN:
+ printf("modbus_main: Protocol stack is shutting down\n");
+ break;
+
+ default:
+ fprintf(stderr, "modbus_main: "
+ "ERROR: Invalid thread state: %d\n",
+ g_modbus.threadstate);
+ break;
+ }
+ break;
+
+ case 'q': /* Quit application */
+ g_modbus.quit = true;
+ pthread_kill(g_modbus.threadid, 9);
+ break;
+
+ case 'h': /* Show help info */
+ modbus_showusage(argv[0], EXIT_SUCCESS);
+ break;
+
+ default:
+ fprintf(stderr, "modbus_main: "
+ "ERROR: Unrecognized option: '%c'\n", option);
+ modbus_showusage(argv[0], EXIT_FAILURE);
+ break;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/****************************************************************************
+ * Name: eMBRegInputCB
+ *
+ * Description:
+ * Required FreeModBus callback function
+ *
+ ****************************************************************************/
+
+eMBErrorCode eMBRegInputCB(uint8_t *buffer, uint16_t address, uint16_t nregs)
+{
+ eMBErrorCode mberr = MB_ENOERR;
+ int index;
+
+ if ((address >= CONFIG_EXAMPLES_MODBUS_REG_INPUT_START) &&
+ (address + nregs <=
+ CONFIG_EXAMPLES_MODBUS_REG_INPUT_START +
+ CONFIG_EXAMPLES_MODBUS_REG_INPUT_NREGS))
+ {
+ index = (int)(address - CONFIG_EXAMPLES_MODBUS_REG_INPUT_START);
+ while (nregs > 0)
+ {
+ *buffer++ = (uint8_t)(g_modbus.reginput[index] >> 8);
+ *buffer++ = (uint8_t)(g_modbus.reginput[index] & 0xff);
+ index++;
+ nregs--;
+ }
+ }
+ else
+ {
+ mberr = MB_ENOREG;
+ }
+
+ return mberr;
+}
+
+/****************************************************************************
+ * Name: eMBRegHoldingCB
+ *
+ * Description:
+ * Required FreeModBus callback function
+ *
+ ****************************************************************************/
+
+eMBErrorCode eMBRegHoldingCB(uint8_t *buffer, uint16_t address, uint16_t nregs,
+ eMBRegisterMode mode)
+{
+ eMBErrorCode mberr = MB_ENOERR;
+ int index;
+
+ if ((address >= CONFIG_EXAMPLES_MODBUS_REG_HOLDING_START) &&
+ (address + nregs <=
+ CONFIG_EXAMPLES_MODBUS_REG_HOLDING_START +
+ CONFIG_EXAMPLES_MODBUS_REG_HOLDING_NREGS))
+ {
+ index = (int)(address - CONFIG_EXAMPLES_MODBUS_REG_HOLDING_START);
+ switch (mode)
+ {
+ /* Pass current register values to the protocol stack. */
+ case MB_REG_READ:
+ while (nregs > 0)
+ {
+ *buffer++ = (uint8_t)(g_modbus.regholding[index] >> 8);
+ *buffer++ = (uint8_t)(g_modbus.regholding[index] & 0xff);
+ index++;
+ nregs--;
+ }
+ break;
+
+ /* Update current register values with new values from the
+ * protocol stack.
+ */
+
+ case MB_REG_WRITE:
+ while (nregs > 0)
+ {
+ g_modbus.regholding[index] = *buffer++ << 8;
+ g_modbus.regholding[index] |= *buffer++;
+ index++;
+ nregs--;
+ }
+ break;
+ }
+ }
+ else
+ {
+ mberr = MB_ENOREG;
+ }
+
+ return mberr;
+}
+
+/****************************************************************************
+ * Name: eMBRegCoilsCB
+ *
+ * Description:
+ * Required FreeModBus callback function
+ *
+ ****************************************************************************/
+
+eMBErrorCode eMBRegCoilsCB(uint8_t *buffer, uint16_t address, uint16_t ncoils,
+ eMBRegisterMode mode)
+{
+ return MB_ENOREG;
+}
+
+/****************************************************************************
+ * Name: eMBRegDiscreteCB
+ *
+ * Description:
+ * Required FreeModBus callback function
+ *
+ ****************************************************************************/
+
+eMBErrorCode eMBRegDiscreteCB(uint8_t *buffer, uint16_t address, uint16_t ndiscrete)
+{
+ return MB_ENOREG;
+}
diff --git a/apps/examples/mount/Kconfig b/apps/examples/mount/Kconfig
new file mode 100644
index 000000000..b38c4763c
--- /dev/null
+++ b/apps/examples/mount/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_MOUNT
+ bool "File system mount example"
+ default n
+ ---help---
+ Enable the file system mount example
+
+if EXAMPLES_MOUNT
+endif
diff --git a/apps/examples/mount/Makefile b/apps/examples/mount/Makefile
new file mode 100644
index 000000000..69cf970cf
--- /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 <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
+
+# 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..c75686086
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..e0eb8a615
--- /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 <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 <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: mount_main
+ ****************************************************************************/
+
+int mount_main(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("mount_main: ERROR failed to create RAM disk\n");
+ return 1;
+ }
+#endif
+
+ /* Mount the test file system (see arch/sim/src/up_deviceimage.c */
+
+ printf("mount_main: 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("mount_main: 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("mount_main: Try unmount(%s)\n", g_target);
+
+ ret = umount(g_target);
+ if (ret != 0)
+ {
+ printf("mount_main: ERROR umount() failed, errno %d\n", errno);
+ g_nerrors++;
+ }
+
+ printf("mount_main: %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..83ef74e42
--- /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 <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 <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <nuttx/ramdisk.h>
+#include <nuttx/fs/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/Kconfig b/apps/examples/nettest/Kconfig
new file mode 100644
index 000000000..63d34ec3f
--- /dev/null
+++ b/apps/examples/nettest/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NETTEST
+ bool "Network test example"
+ default n
+ ---help---
+ Enable the network test example
+
+if EXAMPLES_NETTEST
+endif
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..b95d9da62
--- /dev/null
+++ b/apps/examples/nettest/nettest.c
@@ -0,0 +1,109 @@
+/****************************************************************************
+ * 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 <nuttx/net/uip/uip.h>
+#include <apps/netutils/uiplib.h>
+
+#include "nettest.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * nettest_main
+ ****************************************************************************/
+
+int nettest_main(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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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..be33215cf
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..d498feb31
--- /dev/null
+++ b/apps/examples/nettest/nettest_client.c
@@ -0,0 +1,210 @@
+/****************************************************************************
+ * examples/nettest/nettest-client.c
+ *
+ * Copyright (C) 2007, 2011-2012 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;
+ }
+ else if (nbytesrecvd == 0)
+ {
+ message("client: The server closed the connection\n");
+ 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..76a20e652
--- /dev/null
+++ b/apps/examples/nettest/nettest_server.c
@@ -0,0 +1,245 @@
+/****************************************************************************
+ * examples/nettest/nettest-server.c
+ *
+ * Copyright (C) 2007, 2011-2012 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;
+ }
+ else if (nbytesread == 0)
+ {
+ message("server: The client broke the connection\n");
+ 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;
+ }
+ else if (nbytesread == 0)
+ {
+ message("server: The client broke the connection\n");
+ 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/Kconfig b/apps/examples/nsh/Kconfig
new file mode 100644
index 000000000..309aa925e
--- /dev/null
+++ b/apps/examples/nsh/Kconfig
@@ -0,0 +1,15 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NSH
+ bool "NuttShell (NSH) example"
+ default n
+ select NSH_LIBRARY
+ select SYSTEM_READLINE
+ ---help---
+ Enable the NuttShell (NSH) example
+
+if EXAMPLES_NSH
+endif
diff --git a/apps/examples/nsh/Makefile b/apps/examples/nsh/Makefile
new file mode 100644
index 000000000..bad40fb2e
--- /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 <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
+
+# 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..97792cb2a
--- /dev/null
+++ b/apps/examples/nsh/nsh_main.c
@@ -0,0 +1,136 @@
+/****************************************************************************
+ * examples/nsh/nsh_main.c
+ *
+ * Copyright (C) 2007-2012 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/stat.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sched.h>
+#include <errno.h>
+
+#include <nuttx/arch.h>
+
+#include <apps/nsh.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* The NSH telnet console requires networking support (and TCP/IP) */
+
+#ifndef CONFIG_NET
+# undef CONFIG_NSH_TELNET
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_main
+ ****************************************************************************/
+
+int nsh_main(int argc, char *argv[])
+{
+ int exitval = 0;
+ int ret;
+
+ /* Call all C++ static constructors */
+
+#if defined(CONFIG_HAVE_CXX) && defined(CONFIG_HAVE_CXXINITIALIZE)
+ up_cxxinitialize();
+#endif
+
+ /* Initialize the NSH library */
+
+ nsh_initialize();
+
+ /* If the Telnet console is selected as a front-end, then start the
+ * Telnet daemon.
+ */
+
+#ifdef CONFIG_NSH_TELNET
+ ret = nsh_telnetstart();
+ 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", ret);
+ exitval = 1;
+ }
+#endif
+
+ /* If the serial console front end is selected, then run it on this thread */
+
+#ifdef CONFIG_NSH_CONSOLE
+ ret = nsh_consolemain(0, NULL);
+
+ /* nsh_consolemain() should not return. So if we get here, something
+ * is wrong.
+ */
+
+ fprintf(stderr, "ERROR: nsh_consolemain() returned: %d\n", ret);
+ exitval = 1;
+#endif
+
+ return exitval;
+}
diff --git a/apps/examples/null/Kconfig b/apps/examples/null/Kconfig
new file mode 100644
index 000000000..1f19dfd2c
--- /dev/null
+++ b/apps/examples/null/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NULL
+ bool "NULL example"
+ default n
+ ---help---
+ Enable the NULL example
+
+if EXAMPLES_NULL
+endif
diff --git a/apps/examples/null/Makefile b/apps/examples/null/Makefile
new file mode 100644
index 000000000..634120600
--- /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 <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
+
+# 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..c4624bd1d
--- /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 <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
+ ****************************************************************************/
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: null_main
+ ****************************************************************************/
+
+int null_main(int argc, char *argv[])
+{
+ return 0;
+}
diff --git a/apps/examples/nx/Kconfig b/apps/examples/nx/Kconfig
new file mode 100644
index 000000000..2081b12dc
--- /dev/null
+++ b/apps/examples/nx/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NX
+ bool "NX graphics example"
+ default n
+ ---help---
+ Enable the NX graphics example
+
+if EXAMPLES_NX
+endif
diff --git a/apps/examples/nx/Makefile b/apps/examples/nx/Makefile
new file mode 100644
index 000000000..748d67210
--- /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 <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
+
+# 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..329e5c533
--- /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 <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 <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..d9a6a2ade
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..df4a0faa1
--- /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 <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 <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..04fc10e28
--- /dev/null
+++ b/apps/examples/nx/nx_main.c
@@ -0,0 +1,900 @@
+/****************************************************************************
+ * examples/nx/nx_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 <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, &param);
+ 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, &param);
+ (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: nx_main
+ ****************************************************************************/
+
+int nx_main(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("nx_main: NX handle=%p\n", g_hnx);
+ if (!g_hnx || ret < 0)
+ {
+ message("nx_main: 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("nx_main: Failed to get font handle: %d\n", errno);
+ g_exitcode = NXEXIT_FONTOPEN;
+ goto errout;
+ }
+
+ /* Set the background to the configured background color */
+
+ message("nx_main: Set background color=%d\n", CONFIG_EXAMPLES_NX_BGCOLOR);
+ color = CONFIG_EXAMPLES_NX_BGCOLOR;
+ ret = nx_setbgcolor(g_hnx, &color);
+ if (ret < 0)
+ {
+ message("nx_main: nx_setbgcolor failed: %d\n", errno);
+ g_exitcode = NXEXIT_NXSETBGCOLOR;
+ goto errout_with_nx;
+ }
+
+ /* Create window #1 */
+
+ message("nx_main: Create window #1\n");
+ nxeg_initstate(&g_wstate[0], 1, CONFIG_EXAMPLES_NX_COLOR1);
+ hwnd1 = nxeg_openwindow(&g_nxcb, &g_wstate[0]);
+ message("nx_main: 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("nx_main: 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("nx_main: 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("nx_main: Sleeping\n\n");
+ sleep(1);
+
+ /* Set the position of window #1 */
+
+ pt.x = g_xres / 8;
+ pt.y = g_yres / 8;
+
+ message("nx_main: 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("nx_main: Sleeping\n\n");
+ sleep(1);
+
+ /* Open the toolbar */
+
+#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS
+ message("nx_main: 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("nx_main: Sleeping\n\n");
+ sleep(1);
+#endif
+
+ /* Create window #2 */
+
+ message("nx_main: Create window #2\n");
+ nxeg_initstate(&g_wstate[1], 2, CONFIG_EXAMPLES_NX_COLOR2);
+ hwnd2 = nxeg_openwindow(&g_nxcb, &g_wstate[1]);
+ message("nx_main: hwnd2=%p\n", hwnd2);
+ if (!hwnd2)
+ {
+ goto errout_with_hwnd1;
+ }
+
+ /* Sleep a bit */
+
+ message("nx_main: Sleeping\n\n");
+ sleep(1);
+
+ /* Set the size of the window 2 == size of window 1*/
+
+ message("nx_main: 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("nx_main: 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("nx_main: 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("nx_main: Sleeping\n\n");
+ sleep(1);
+
+#ifndef CONFIG_EXAMPLES_NX_RAWWINDOWS
+ message("nx_main: 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("nx_main: Sleeping\n\n");
+ sleep(1);
+#endif
+
+ /* Give keyboard input to the top window -- should be window #2 */
+
+#ifdef CONFIG_NX_KBD
+ message("nx_main: Send keyboard input: %s\n", g_kbdmsg1);
+ ret = nx_kbdin(g_hnx, strlen((FAR const char *)g_kbdmsg1), g_kbdmsg1);
+ if (ret < 0)
+ {
+ message("nx_main: nx_kbdin failed: %d\n", errno);
+ goto errout_with_hwnd2;
+ }
+
+ /* Sleep a bit */
+
+ message("nx_main: Sleeping\n\n");
+ sleep(1);
+#endif
+
+ /* Lower window 2 */
+
+ message("nx_main: Lower window #2\n");
+ ret = nxeg_lower(hwnd2);
+ if (ret < 0)
+ {
+ goto errout_with_hwnd2;
+ }
+
+ /* Sleep a bit */
+
+ message("nx_main: 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("nx_main: Sleeping\n\n");
+ sleep(1);
+#endif
+
+ /* Give keyboard input to the top window -- should be window #1 */
+
+#ifdef CONFIG_NX_KBD
+ message("nx_main: Send keyboard input: %s\n", g_kbdmsg2);
+ ret = nx_kbdin(g_hnx, strlen((FAR const char *)g_kbdmsg2), g_kbdmsg2);
+ if (ret < 0)
+ {
+ message("nx_main: nx_kbdin failed: %d\n", errno);
+ goto errout_with_hwnd2;
+ }
+
+ /* Sleep a bit */
+
+ message("nx_main: Sleeping\n\n");
+ sleep(1);
+#endif
+
+ /* Raise window 2 */
+
+ message("nx_main: 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("nx_main: Sleeping\n\n");
+ sleep(2);
+
+ /* Close the window 2 */
+
+errout_with_hwnd2:
+ message("nx_main: Close window #2\n");
+ (void)nxeg_closewindow(hwnd2, &g_wstate[1]);
+
+ /* Close the window1 */
+
+errout_with_hwnd1:
+ message("nx_main: Close window #1\n");
+ (void)nxeg_closewindow(hwnd1, &g_wstate[0]);
+
+errout_with_nx:
+#ifdef CONFIG_NX_MULTIUSER
+ /* Disconnect from the server */
+
+ message("nx_main: Disconnect from the server\n");
+ nx_disconnect(g_hnx);
+#else
+ /* Close the server */
+
+ message("nx_main: 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..7f3ee5dfc
--- /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 <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 <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/nxconsole/Kconfig b/apps/examples/nxconsole/Kconfig
new file mode 100644
index 000000000..a52c49453
--- /dev/null
+++ b/apps/examples/nxconsole/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NXCONSOLE
+ bool "NxConsole example"
+ default n
+ ---help---
+ Enable the NxConsole example
+
+if EXAMPLES_NXCONSOLE
+endif
diff --git a/apps/examples/nxconsole/Makefile b/apps/examples/nxconsole/Makefile
new file mode 100644
index 000000000..78a96a25d
--- /dev/null
+++ b/apps/examples/nxconsole/Makefile
@@ -0,0 +1,93 @@
+############################################################################
+# apps/examples/nxconsole/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
+
+# NuttX NX Console Example.
+
+ASRCS =
+CSRCS = nxcon_main.c nxcon_toolbar.c nxcon_wndo.c nxcon_server.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/examples/nxconsole/nxcon_internal.h b/apps/examples/nxconsole/nxcon_internal.h
new file mode 100644
index 000000000..c5ad760ad
--- /dev/null
+++ b/apps/examples/nxconsole/nxcon_internal.h
@@ -0,0 +1,310 @@
+/****************************************************************************
+ * examples/nxconsole/nxcon_internal.h
+ *
+ * Copyright (C) 2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __EXAMPLES_NXCONSOLE_NXCON_INTERNAL_H
+#define __EXAMPLES_NXCONSOLE_NXCON_INTERNAL_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <semaphore.h>
+
+#include <nuttx/rgbcolors.h>
+
+#include <nuttx/nx/nx.h>
+#include <nuttx/nx/nxglib.h>
+#include <nuttx/nx/nxtk.h>
+#include <nuttx/nx/nxconsole.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* Need NX graphics support */
+
+#ifndef CONFIG_NX
+# error "NX is not enabled (CONFIG_NX=y)"
+#endif
+
+/* Can't do the NxConsole example if the NxConsole driver is not built */
+
+#ifndef CONFIG_NXCONSOLE
+# error "NxConsole is not enabled (CONFIG_NXCONSOLE=y)"
+#endif
+
+/* NxConsole requires NX Multi-user mode */
+
+#ifndef CONFIG_NX_MULTIUSER
+# error "Multi-user NX support is required (CONFIG_NX_MULTIUSER=y)"
+#endif
+
+/* If there is no NSH console, then why are we running this example? */
+
+#ifndef CONFIG_NSH_CONSOLE
+# warning "Expected CONFIG_NSH_CONSOLE=y"
+#endif
+
+/* The NSH telnet console requires networking support (and TCP/IP) */
+
+#ifndef CONFIG_NET
+# undef CONFIG_NSH_TELNET
+#endif
+
+/* If not specified, assume that the hardware supports one video plane */
+
+#if CONFIG_NX_NPLANES != 1
+# error "Only CONFIG_NX_NPLANES==1 supported"
+#endif
+
+#ifndef CONFIG_EXAMPLES_NXCON_VPLANE
+# define CONFIG_EXAMPLES_NXCON_VPLANE 0
+#endif
+
+/* Pixel depth. If none provided, pick the smallest enabled pixel depth */
+
+#ifndef CONFIG_EXAMPLES_NXCON_BPP
+# if !defined(CONFIG_NX_DISABLE_1BPP)
+# define CONFIG_EXAMPLES_NXCON_BPP 1
+# elif !defined(CONFIG_NX_DISABLE_2BPP)
+# define CONFIG_EXAMPLES_NXCON_BPP 2
+# elif !defined(CONFIG_NX_DISABLE_4BPP)
+# define CONFIG_EXAMPLES_NXCON_BPP 4
+# elif !defined(CONFIG_NX_DISABLE_8BPP)
+# define CONFIG_EXAMPLES_NXCON_BPP 8
+# elif !defined(CONFIG_NX_DISABLE_16BPP)
+# define CONFIG_EXAMPLES_NXCON_BPP 16
+//#elif !defined(CONFIG_NX_DISABLE_24BPP)
+//# define CONFIG_NXCONSOLE_BPP 24
+# elif !defined(CONFIG_NX_DISABLE_32BPP)
+# define CONFIG_EXAMPLES_NXCON_BPP 32
+# else
+# error "No pixel depth provided"
+# endif
+#endif
+
+/* Background color (default is darker royal blue) */
+
+#ifndef CONFIG_EXAMPLES_NXCON_BGCOLOR
+# if CONFIG_EXAMPLES_NXCON_BPP == 24 || CONFIG_EXAMPLES_NXCON_BPP == 32
+# define CONFIG_EXAMPLES_NXCON_BGCOLOR RGBTO24(39, 64, 139)
+# elif CONFIG_EXAMPLES_NXCON_BPP == 16
+# define CONFIG_EXAMPLES_NXCON_BGCOLOR RGBTO16(39, 64, 139)
+# else
+# define CONFIG_EXAMPLES_NXCON_BGCOLOR RGBTO8(39, 64, 139)
+# endif
+#endif
+
+/* Window color (lighter steel blue) */
+
+#ifndef CONFIG_EXAMPLES_NXCON_WCOLOR
+# if CONFIG_EXAMPLES_NXCON_BPP == 24 || CONFIG_EXAMPLES_NXCON_BPP == 32
+# define CONFIG_EXAMPLES_NXCON_WCOLOR RGBTO24(202, 225, 255)
+# elif CONFIG_EXAMPLES_NXCON_BPP == 16
+# define CONFIG_EXAMPLES_NXCON_WCOLOR RGBTO16(202, 225, 255)
+# else
+# define CONFIG_EXAMPLES_NXCON_WCOLOR RGBTO8(202, 225, 255)
+# endif
+#endif
+
+/* Toolbar color (medium grey) */
+
+#ifndef CONFIG_EXAMPLES_NXCON_TBCOLOR
+# if CONFIG_EXAMPLES_NX_BPP == 24 || CONFIG_EXAMPLES_NX_BPP == 32
+# define CONFIG_EXAMPLES_NXCON_TBCOLOR RGBTO24(188, 188, 188)
+# elif CONFIG_EXAMPLES_NX_BPP == 16
+# define CONFIG_EXAMPLES_NXCON_TBCOLOR RGBTO16(188, 188, 188)
+# else
+# define CONFIG_EXAMPLES_NXCON_TBCOLOR RGBTO8(188, 188, 188)
+# endif
+#endif
+
+/* Font ID */
+
+#ifndef CONFIG_EXAMPLES_NXCON_FONTID
+# define CONFIG_EXAMPLES_NXCON_FONTID NXFONT_DEFAULT
+#endif
+
+/* Font color */
+
+#ifndef CONFIG_EXAMPLES_NXCON_FONTCOLOR
+# if CONFIG_EXAMPLES_NXCON_BPP == 24 || CONFIG_EXAMPLES_NXCON_BPP == 32
+# define CONFIG_EXAMPLES_NXCON_FONTCOLOR RGBTO24(0, 0, 0)
+# elif CONFIG_EXAMPLES_NXCON_BPP == 16
+# define CONFIG_EXAMPLES_NXCON_FONTCOLOR RGBTO16(0, 0, 0)
+# else
+# define CONFIG_EXAMPLES_NXCON_FONTCOLOR RGBTO8(0, 0, 0)
+# endif
+#endif
+
+/* Height of the toolbar */
+
+#ifndef CONFIG_EXAMPLES_NXCON_TOOLBAR_HEIGHT
+# define CONFIG_EXAMPLES_NXCON_TOOLBAR_HEIGHT 16
+#endif
+
+/* Multi-user NX support */
+
+#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_NXCON_STACKSIZE
+# define CONFIG_EXAMPLES_NXCON_STACKSIZE 2048
+#endif
+#ifndef CONFIG_EXAMPLES_NXCON_LISTENERPRIO
+# define CONFIG_EXAMPLES_NXCON_LISTENERPRIO 100
+#endif
+#ifndef CONFIG_EXAMPLES_NXCON_CLIENTPRIO
+# define CONFIG_EXAMPLES_NXCON_CLIENTPRIO 100
+#endif
+#ifndef CONFIG_EXAMPLES_NXCON_SERVERPRIO
+# define CONFIG_EXAMPLES_NXCON_SERVERPRIO 120
+#endif
+#ifndef CONFIG_EXAMPLES_NXCON_NOTIFYSIGNO
+# define CONFIG_EXAMPLES_NXCON_NOTIFYSIGNO 4
+#endif
+
+/* Graphics Device */
+
+#ifndef CONFIG_EXAMPLES_NXCON_DEVNO
+# define CONFIG_EXAMPLES_NXCON_DEVNO 0
+#endif
+
+/* NX Console Device */
+
+#ifndef CONFIG_EXAMPLES_NXCON_MINOR
+# define CONFIG_EXAMPLES_NXCON_MINOR 0
+#endif
+
+#ifndef CONFIG_EXAMPLES_NXCON_DEVNAME
+# define CONFIG_EXAMPLES_NXCON_DEVNAME "/dev/nxcon0"
+#endif
+
+/* NxConsole task */
+
+#ifndef CONFIG_EXAMPLES_NXCONSOLE_PRIO
+# define CONFIG_EXAMPLES_NXCONSOLE_PRIO SCHED_PRIORITY_DEFAULT
+#endif
+
+#ifndef CONFIG_EXAMPLES_NXCONSOLE_STACKSIZE
+# define CONFIG_EXAMPLES_NXCONSOLE_STACKSIZE 2048
+#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 example global variables are retained in a structure to minimize
+ * the chance of name collisions.
+ */
+
+struct nxcon_state_s
+{
+ volatile bool haveres; /* True: Have screen resolution */
+ volatile bool connected; /* True: Connected to server */
+ sem_t eventsem; /* Control waiting for display events */
+ pid_t pid; /* Console task ID */
+ NXHANDLE hnx; /* The connection handler */
+ NXTKWINDOW hwnd; /* The window */
+ NXCONSOLE hdrvr; /* The console driver */
+ struct nxcon_window_s wndo; /* Describes the window */
+ nxgl_coord_t xres; /* Screen X resolution */
+ nxgl_coord_t yres; /* Screen Y resolution */
+ struct nxgl_size_s wsize; /* Window size */
+ struct nxgl_point_s wpos; /* Window position */
+};
+
+/****************************************************************************
+ * Public Variables
+ ****************************************************************************/
+/* All example global variables are retained in a structure to minimize
+ * the chance of name collisions.
+ */
+
+extern struct nxcon_state_s g_nxcon_vars;
+
+/* NX callback vtables */
+
+extern const struct nx_callback_s g_nxconcb;
+extern const struct nx_callback_s g_nxtoolcb;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+/* Board-specific driver intiialization */
+
+#ifdef CONFIG_EXAMPLES_NXCON_EXTERNINIT
+extern FAR NX_DRIVERTYPE *up_nxdrvinit(unsigned int devno);
+#endif
+
+/* Server thread support */
+
+extern int nxcon_server(int argc, char *argv[]);
+extern FAR void *nxcon_listener(FAR void *arg);
+
+#endif /* __EXAMPLES_NXCONSOLE_NXCON_INTERNAL_H */
diff --git a/apps/examples/nxconsole/nxcon_main.c b/apps/examples/nxconsole/nxcon_main.c
new file mode 100644
index 000000000..41d8efd19
--- /dev/null
+++ b/apps/examples/nxconsole/nxcon_main.c
@@ -0,0 +1,412 @@
+/****************************************************************************
+ * examples/nxconsole/nxcon_main.c
+ *
+ * Copyright (C) 2012 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 <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.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 <nuttx/nx/nxconsole.h>
+
+#include <apps/nsh.h>
+
+#include "nxcon_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* All example global variables are retained in a structure to minimize
+ * the chance of name collisions.
+ */
+
+struct nxcon_state_s g_nxcon_vars;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxcon_initialize
+ ****************************************************************************/
+
+static int nxcon_initialize(void)
+{
+ struct sched_param param;
+ pthread_t thread;
+ pid_t servrid;
+ int ret;
+
+ /* Set the client task priority */
+
+ param.sched_priority = CONFIG_EXAMPLES_NXCON_CLIENTPRIO;
+ ret = sched_setparam(0, &param);
+ if (ret < 0)
+ {
+ message("nxcon_initialize: sched_setparam failed: %d\n" , ret);
+ return ERROR;
+ }
+
+ /* Start the server task */
+
+ message("nxcon_initialize: Starting nxcon_server task\n");
+ servrid = task_create("NX Server", CONFIG_EXAMPLES_NXCON_SERVERPRIO,
+ CONFIG_EXAMPLES_NXCON_STACKSIZE, nxcon_server, NULL);
+ if (servrid < 0)
+ {
+ message("nxcon_initialize: Failed to create nxcon_server task: %d\n", errno);
+ return ERROR;
+ }
+
+ /* Wait a bit to let the server get started */
+
+ sleep(1);
+
+ /* Connect to the server */
+
+ g_nxcon_vars.hnx = nx_connect();
+ if (g_nxcon_vars.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_NXCON_LISTENERPRIO;
+ (void)pthread_attr_setschedparam(&attr, &param);
+ (void)pthread_attr_setstacksize(&attr, CONFIG_EXAMPLES_NXCON_STACKSIZE);
+
+ ret = pthread_create(&thread, &attr, nxcon_listener, NULL);
+ if (ret != 0)
+ {
+ printf("nxcon_initialize: pthread_create failed: %d\n", ret);
+ return ERROR;
+ }
+
+ /* Don't return until we are connected to the server */
+
+ while (!g_nxcon_vars.connected)
+ {
+ /* Wait for the listener thread to wake us up when we really
+ * are connected.
+ */
+
+ (void)sem_wait(&g_nxcon_vars.eventsem);
+ }
+ }
+ else
+ {
+ message("nxcon_initialize: nx_connect failed: %d\n", errno);
+ return ERROR;
+ }
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nxcon_task
+ ****************************************************************************/
+
+static int nxcon_task(int argc, char **argv)
+{
+ /* If the console front end is selected, then run it on this thread */
+
+#ifdef CONFIG_NSH_CONSOLE
+ (void)nsh_consolemain(0, NULL);
+#endif
+
+ printf("nxcon_task: Unregister the NX console device\n");
+ (void)nxcon_unregister(g_nxcon_vars.hdrvr);
+
+ printf("nxcon_task: Close the window\n");
+ (void)nxtk_closewindow(g_nxcon_vars.hwnd);
+
+ /* Disconnect from the server */
+
+ printf("nxcon_task: Disconnect from the server\n");
+ nx_disconnect(g_nxcon_vars.hnx);
+
+ return EXIT_SUCCESS;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxcon_main
+ ****************************************************************************/
+
+int nxcon_main(int argc, char **argv)
+{
+ nxgl_mxpixel_t color;
+ int fd;
+ int ret;
+
+ /* General Initialization *************************************************/
+ /* Reset all global data */
+
+ message("nxcon_main: Started\n");
+ memset(&g_nxcon_vars, 0, sizeof(struct nxcon_state_s));
+
+ /* Call all C++ static constructors */
+
+#if defined(CONFIG_HAVE_CXX) && defined(CONFIG_HAVE_CXXINITIALIZE)
+ up_cxxinitialize();
+#endif
+
+ /* NSH Initialization *****************************************************/
+ /* Initialize the NSH library */
+
+ message("nxcon_main: Initialize NSH\n");
+ nsh_initialize();
+
+ /* If the Telnet console is selected as a front-end, then start the
+ * Telnet daemon.
+ */
+
+#ifdef CONFIG_NSH_TELNET
+ ret = nsh_telnetstart();
+ 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", ret);
+ }
+#endif
+ /* NX Initialization ******************************************************/
+ /* Initialize NX */
+
+ message("nxcon_main: Initialize NX\n");
+ ret = nxcon_initialize();
+ message("nxcon_main: NX handle=%p\n", g_nxcon_vars.hnx);
+ if (!g_nxcon_vars.hnx || ret < 0)
+ {
+ message("nxcon_main: Failed to get NX handle: %d\n", errno);
+ goto errout;
+ }
+
+ /* Set the background to the configured background color */
+
+ message("nxcon_main: Set background color=%d\n", CONFIG_EXAMPLES_NXCON_BGCOLOR);
+ color = CONFIG_EXAMPLES_NXCON_BGCOLOR;
+ ret = nx_setbgcolor(g_nxcon_vars.hnx, &color);
+ if (ret < 0)
+ {
+ message("nxcon_main: nx_setbgcolor failed: %d\n", errno);
+ goto errout_with_nx;
+ }
+
+ /* Window Configuration ***************************************************/
+ /* Create a window */
+
+ message("nxcon_main: Create window\n");
+ g_nxcon_vars.hwnd = nxtk_openwindow(g_nxcon_vars.hnx, &g_nxconcb, NULL);
+ if (!g_nxcon_vars.hwnd)
+ {
+ message("nxcon_main: nxtk_openwindow failed: %d\n", errno);
+ goto errout_with_nx;
+ }
+ message("nxcon_main: hwnd=%p\n", g_nxcon_vars.hwnd);
+
+ /* Wait until we have the screen resolution. We'll have this immediately
+ * unless we are dealing with the NX server.
+ */
+
+ while (!g_nxcon_vars.haveres)
+ {
+ (void)sem_wait(&g_nxcon_vars.eventsem);
+ }
+ message("nxcon_main: Screen resolution (%d,%d)\n", g_nxcon_vars.xres, g_nxcon_vars.yres);
+
+ /* Determine the size and position of the window */
+
+ g_nxcon_vars.wndo.wsize.w = g_nxcon_vars.xres / 2 + g_nxcon_vars.xres / 4;
+ g_nxcon_vars.wndo.wsize.h = g_nxcon_vars.yres / 2 + g_nxcon_vars.yres / 4;
+
+ g_nxcon_vars.wpos.x = g_nxcon_vars.xres / 8;
+ g_nxcon_vars.wpos.y = g_nxcon_vars.yres / 8;
+
+ /* Set the window position */
+
+ message("nxcon_main: Set window position to (%d,%d)\n",
+ g_nxcon_vars.wpos.x, g_nxcon_vars.wpos.y);
+
+ ret = nxtk_setposition(g_nxcon_vars.hwnd, &g_nxcon_vars.wpos);
+ if (ret < 0)
+ {
+ message("nxcon_main: nxtk_setposition failed: %d\n", errno);
+ goto errout_with_hwnd;
+ }
+
+ /* Set the window size */
+
+ message("nxcon_main: Set window size to (%d,%d)\n",
+ g_nxcon_vars.wndo.wsize.w, g_nxcon_vars.wndo.wsize.h);
+
+ ret = nxtk_setsize(g_nxcon_vars.hwnd, &g_nxcon_vars.wndo.wsize);
+ if (ret < 0)
+ {
+ message("nxcon_main: nxtk_setsize failed: %d\n", errno);
+ goto errout_with_hwnd;
+ }
+
+ /* Open the toolbar */
+
+ message("nxcon_main: Add toolbar to window\n");
+ ret = nxtk_opentoolbar(g_nxcon_vars.hwnd, CONFIG_EXAMPLES_NXCON_TOOLBAR_HEIGHT, &g_nxtoolcb, NULL);
+ if (ret < 0)
+ {
+ message("nxcon_main: nxtk_opentoolbar failed: %d\n", errno);
+ goto errout_with_hwnd;
+ }
+
+ /* Sleep a little bit to allow the server to catch up */
+
+ sleep(2);
+
+ /* NxConsole Configuration ************************************************/
+ /* Use the window to create an NX console */
+
+ g_nxcon_vars.wndo.wcolor[0] = CONFIG_EXAMPLES_NXCON_WCOLOR;
+ g_nxcon_vars.wndo.fcolor[0] = CONFIG_EXAMPLES_NXCON_FONTCOLOR;
+ g_nxcon_vars.wndo.fontid = CONFIG_EXAMPLES_NXCON_FONTID;
+
+ g_nxcon_vars.hdrvr = nxtk_register(g_nxcon_vars.hwnd, &g_nxcon_vars.wndo, CONFIG_EXAMPLES_NXCON_MINOR);
+ if (!g_nxcon_vars.hdrvr)
+ {
+ message("nxcon_main: nxtk_register failed: %d\n", errno);
+ goto errout_with_hwnd;
+ }
+
+ /* Open the NxConsole driver */
+
+ fd = open(CONFIG_EXAMPLES_NXCON_DEVNAME, O_WRONLY);
+ if (fd < 0)
+ {
+ message("nxcon_main: open %s read-only failed: %d\n",
+ CONFIG_EXAMPLES_NXCON_DEVNAME, errno);
+ goto errout_with_driver;
+ }
+
+ /* Start Console Task *****************************************************/
+ /* Now re-direct stdout and stderr so that they use the NX console driver.
+ * Note that stdin is retained (file descriptor 0, probably the the serial console).
+ */
+
+ message("nxcon_main: Starting the console task\n");
+ msgflush();
+
+ (void)fflush(stdout);
+ (void)fflush(stderr);
+
+ (void)fclose(stdout);
+ (void)fclose(stderr);
+
+ (void)dup2(fd, 1);
+ (void)dup2(fd, 2);
+
+ /* And we can close our original driver file descriptor */
+
+ close(fd);
+
+ /* And start the console task. It will inherit stdin, stdout, and stderr
+ * from this task.
+ */
+
+ g_nxcon_vars.pid = TASK_CREATE("NxConsole", CONFIG_EXAMPLES_NXCONSOLE_PRIO,
+ CONFIG_EXAMPLES_NXCONSOLE_STACKSIZE,
+ nxcon_task, NULL);
+ ASSERT(g_nxcon_vars.pid > 0);
+ return EXIT_SUCCESS;
+
+ /* Error Exits ************************************************************/
+
+errout_with_driver:
+ (void)nxcon_unregister(g_nxcon_vars.hdrvr);
+
+errout_with_hwnd:
+ (void)nxtk_closewindow(g_nxcon_vars.hwnd);
+
+errout_with_nx:
+ /* Disconnect from the server */
+
+ nx_disconnect(g_nxcon_vars.hnx);
+errout:
+ return EXIT_FAILURE;
+}
diff --git a/apps/examples/nxconsole/nxcon_server.c b/apps/examples/nxconsole/nxcon_server.c
new file mode 100644
index 000000000..ccd000ec0
--- /dev/null
+++ b/apps/examples/nxconsole/nxcon_server.c
@@ -0,0 +1,189 @@
+/****************************************************************************
+ * examples/nxconsole/nxcon_server.c
+ *
+ * Copyright (C) 2012 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 <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 "nxcon_internal.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxcon_server
+ ****************************************************************************/
+
+int nxcon_server(int argc, char *argv[])
+{
+ FAR NX_DRIVERTYPE *dev;
+ int ret;
+
+#if defined(CONFIG_EXAMPLES_NXCON_EXTERNINIT)
+ /* Use external graphics driver initialization */
+
+ message("nxcon_server: Initializing external graphics device\n");
+ dev = up_nxdrvinit(CONFIG_EXAMPLES_NXCON_DEVNO);
+ if (!dev)
+ {
+ message("nxcon_server: up_nxdrvinit failed, devno=%d\n", CONFIG_EXAMPLES_NXCON_DEVNO);
+ return ERROR;
+ }
+
+#elif defined(CONFIG_NX_LCDDRIVER)
+ /* Initialize the LCD device */
+
+ message("nxcon_server: Initializing LCD\n");
+ ret = up_lcdinitialize();
+ if (ret < 0)
+ {
+ message("nxcon_server: up_lcdinitialize failed: %d\n", -ret);
+ return 1;
+ }
+
+ /* Get the device instance */
+
+ dev = up_lcdgetdev(CONFIG_EXAMPLES_NXCON_DEVNO);
+ if (!dev)
+ {
+ message("nxcon_server: up_lcdgetdev failed, devno=%d\n", CONFIG_EXAMPLES_NXCON_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("nxcon_server: Initializing framebuffer\n");
+ ret = up_fbinitialize();
+ if (ret < 0)
+ {
+ message("nxcon_server: up_fbinitialize failed: %d\n", -ret);
+ return 1;
+ }
+
+ dev = up_fbgetvplane(CONFIG_EXAMPLES_NXCON_VPLANE);
+ if (!dev)
+ {
+ message("nxcon_server: up_fbgetvplane failed, vplane=%d\n", CONFIG_EXAMPLES_NXCON_VPLANE);
+ return 2;
+ }
+#endif
+
+ /* Then start the server */
+
+ ret = nx_run(dev);
+ gvdbg("nx_run returned: %d\n", errno);
+ return 3;
+}
+
+/****************************************************************************
+ * Name: nxcon_listener
+ ****************************************************************************/
+
+FAR void *nxcon_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_nxcon_vars.hnx);
+ if (ret < 0)
+ {
+ /* An error occurred... assume that we have lost connection with
+ * the server.
+ */
+
+ message("nxcon_listener: Lost server connection: %d\n", errno);
+ exit(EXIT_FAILURE);
+ }
+
+ /* If we received a message, we must be connected */
+
+ if (!g_nxcon_vars.connected)
+ {
+ g_nxcon_vars.connected = true;
+ sem_post(&g_nxcon_vars.eventsem);
+ message("nxcon_listener: Connected\n");
+ }
+ }
+}
diff --git a/apps/examples/nxconsole/nxcon_toolbar.c b/apps/examples/nxconsole/nxcon_toolbar.c
new file mode 100644
index 000000000..d4432b2f4
--- /dev/null
+++ b/apps/examples/nxconsole/nxcon_toolbar.c
@@ -0,0 +1,172 @@
+/****************************************************************************
+ * examples/nxconsole/nxcon_toolbar.c
+ *
+ * Copyright (C) 2012 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 <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 "nxcon_internal.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void nxtool_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect,
+ bool morem, FAR void *arg);
+static void nxtool_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 nxtool_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos,
+ uint8_t buttons, FAR void *arg);
+#endif
+
+#ifdef CONFIG_NX_KBD
+static void nxtool_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_nxtoolcb =
+{
+ nxtool_redraw, /* redraw */
+ nxtool_position /* position */
+#ifdef CONFIG_NX_MOUSE
+ , nxtool_mousein /* mousein */
+#endif
+#ifdef CONFIG_NX_KBD
+ , nxtool_kbdin /* my kbdin */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxtool_redraw
+ ****************************************************************************/
+
+static void nxtool_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect,
+ bool more, FAR void *arg)
+{
+ nxgl_mxpixel_t color[CONFIG_NX_NPLANES];
+ int ret;
+
+ 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");
+
+ color[0] = CONFIG_EXAMPLES_NXCON_TBCOLOR;
+ ret = nxtk_filltoolbar(hwnd, rect, color);
+ if (ret < 0)
+ {
+ gdbg("nxtk_filltoolbar failed: %d\n", errno);
+ }
+}
+
+/****************************************************************************
+ * Name: nxtool_position
+ ****************************************************************************/
+
+static void nxtool_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)
+{
+ 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);
+}
+
+/****************************************************************************
+ * Name: nxtool_mousein
+ ****************************************************************************/
+
+#ifdef CONFIG_NX_MOUSE
+static void nxtool_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos,
+ uint8_t buttons, FAR void *arg)
+{
+ gvdbg("hwnd=%p pos=(%d,%d) button=%02x\n", hwnd, pos->x, pos->y, buttons);
+}
+#endif
+
+/****************************************************************************
+ * Name: nxtool_kbdin
+ ****************************************************************************/
+
+#ifdef CONFIG_NX_KBD
+static void nxtool_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch,
+ FAR void *arg)
+{
+ gvdbg("hwnd=%p nch=%d\n", hwnd, nch);
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
diff --git a/apps/examples/nxconsole/nxcon_wndo.c b/apps/examples/nxconsole/nxcon_wndo.c
new file mode 100644
index 000000000..083da739d
--- /dev/null
+++ b/apps/examples/nxconsole/nxcon_wndo.c
@@ -0,0 +1,208 @@
+/****************************************************************************
+ * examples/nxconsole/nxcon_wndo.c
+ *
+ * Copyright (C) 2012 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 <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/nx/nx.h>
+#include <nuttx/nx/nxfonts.h>
+
+#include "nxcon_internal.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void nxwndo_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect,
+ bool morem, FAR void *arg);
+static void nxwndo_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 nxwndo_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos,
+ uint8_t buttons, FAR void *arg);
+#endif
+
+#ifdef CONFIG_NX_KBD
+static void nxwndo_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_nxconcb =
+{
+ nxwndo_redraw, /* redraw */
+ nxwndo_position /* position */
+#ifdef CONFIG_NX_MOUSE
+ , nxwndo_mousein /* mousein */
+#endif
+#ifdef CONFIG_NX_KBD
+ , nxwndo_kbdin /* my kbdin */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxwndo_redraw
+ ****************************************************************************/
+
+static void nxwndo_redraw(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect,
+ bool more, FAR void *arg)
+{
+ nxgl_mxpixel_t wcolor[CONFIG_NX_NPLANES];
+
+ 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");
+
+ /* Don't attempt to redraw if the driver has not yet been opened */
+
+ if (g_nxcon_vars.hdrvr)
+ {
+ /* Inform the NX console of the redraw request */
+
+ nxcon_redraw(g_nxcon_vars.hdrvr, rect, more);
+ }
+ else
+ {
+ /* If the driver has not been opened, then just redraw the window color */
+
+ wcolor[0] = CONFIG_EXAMPLES_NXCON_WCOLOR;
+ (void)nxtk_fillwindow(hwnd, rect, wcolor);
+ }
+}
+
+/****************************************************************************
+ * Name: nxwndo_position
+ ****************************************************************************/
+
+static void nxwndo_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_nxcon_vars.haveres)
+ {
+ /* Save the background window handle */
+
+ g_nxcon_vars.hwnd = hwnd;
+
+ /* Save the background window size */
+
+ g_nxcon_vars.wndo.wsize.w = size->w;
+ g_nxcon_vars.wndo.wsize.h = size->h;
+
+ /* Save the window limits (these should be the same for all places and all windows */
+
+ g_nxcon_vars.xres = bounds->pt2.x + 1;
+ g_nxcon_vars.yres = bounds->pt2.y + 1;
+
+ g_nxcon_vars.haveres = true;
+ sem_post(&g_nxcon_vars.eventsem);
+ gvdbg("Have xres=%d yres=%d\n", g_nxcon_vars.xres, g_nxcon_vars.yres);
+ }
+}
+
+/****************************************************************************
+ * Name: nxwndo_mousein
+ ****************************************************************************/
+
+#ifdef CONFIG_NX_MOUSE
+static void nxwndo_mousein(NXWINDOW hwnd, FAR const struct nxgl_point_s *pos,
+ uint8_t buttons, FAR void *arg)
+{
+ gvdbg("hwnd=%p pos=(%d,%d) button=%02x\n",
+ hwnd, pos->x, pos->y, buttons);
+}
+#endif
+
+/****************************************************************************
+ * Name: nxwndo_kbdin
+ ****************************************************************************/
+
+#ifdef CONFIG_NX_KBD
+static void nxwndo_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch,
+ FAR void *arg)
+{
+ gvdbg("hwnd=%p nch=%d\n", hwnd, nch);
+ (void)write(1, ch, nch);
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
diff --git a/apps/examples/nxffs/Kconfig b/apps/examples/nxffs/Kconfig
new file mode 100644
index 000000000..074ace872
--- /dev/null
+++ b/apps/examples/nxffs/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NXFFS
+ bool "NXFFS file system example"
+ default n
+ ---help---
+ Enable the NXFFS file system example
+
+if EXAMPLES_NXFFS
+endif
diff --git a/apps/examples/nxffs/Makefile b/apps/examples/nxffs/Makefile
new file mode 100644
index 000000000..b3d36e163
--- /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 <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
+
+# 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..5401fc932
--- /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/fs/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: nxffs_main
+ ****************************************************************************/
+
+int nxffs_main(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/Kconfig b/apps/examples/nxflat/Kconfig
new file mode 100644
index 000000000..a3f86488e
--- /dev/null
+++ b/apps/examples/nxflat/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NXFLAT
+ bool "NXFLAT example"
+ default n
+ ---help---
+ Enable the NXFLAT example
+
+if EXAMPLES_NXFLAT
+endif
diff --git a/apps/examples/nxflat/Makefile b/apps/examples/nxflat/Makefile
new file mode 100644
index 000000000..a49177a33
--- /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 <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
+
+# 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..4cd2cd537
--- /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 <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 <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: nxflat_main
+ ****************************************************************************/
+
+int nxflat_main(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..36bb0e88e
--- /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 <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.
+#
+############################################################################
+
+# 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..df3ea1e3e
--- /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 <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
+-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..08a15808a
--- /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 <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 <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..3433145dc
--- /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 <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
+-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..850c2fd4d
--- /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 <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.
+//
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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..3a1798a70
--- /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 <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.
+//
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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..b115010cf
--- /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 <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.
+//
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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..ac718386b
--- /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 <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.
+//
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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..e7e66c628
--- /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 <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
+-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..8ec4e019a
--- /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 <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 <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..47a1c4905
--- /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 <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
+-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..85571261c
--- /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 <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 <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..fe6684856
--- /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 <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
+-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..9a2d5f120
--- /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 <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 <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..f645441ad
--- /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 <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
+-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..f6e89e229
--- /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 <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 <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..222c57dbe
--- /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 <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
+-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..95415fc87
--- /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 <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 <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..69f9dd2f3
--- /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 <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
+-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..bb31d8f71
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..80364b46b
--- /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 <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 <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..2d8b51a2c
--- /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 <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 <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..8b17ec822
--- /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 <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
+-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..192aa49b3
--- /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 <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 <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/Kconfig b/apps/examples/nxhello/Kconfig
new file mode 100644
index 000000000..22f16c9b2
--- /dev/null
+++ b/apps/examples/nxhello/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NXHELLO
+ bool "NX graphics \"Hello, World!\" example"
+ default n
+ ---help---
+ Enable the NX graphics \"Hello, World!\" example
+
+if EXAMPLES_HELLOXX
+endif
diff --git a/apps/examples/nxhello/Makefile b/apps/examples/nxhello/Makefile
new file mode 100644
index 000000000..16e80e15e
--- /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 <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
+
+# 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..2dce7bf6c
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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_nxhellocb;
+
+/****************************************************************************
+ * 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..ad1b99d24
--- /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 <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 <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_nxhellocb =
+{
+ 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..6ee6c69b2
--- /dev/null
+++ b/apps/examples/nxhello/nxhello_main.c
@@ -0,0 +1,286 @@
+/****************************************************************************
+ * examples/nxhello/nxhello_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/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: nxhello_main
+ ****************************************************************************/
+
+int nxhello_main(int argc, char *argv[])
+{
+ nxgl_mxpixel_t color;
+ int ret;
+
+ /* Initialize NX */
+
+ ret = nxhello_initialize();
+ message("nxhello_main: NX handle=%p\n", g_nxhello.hnx);
+ if (!g_nxhello.hnx || ret < 0)
+ {
+ message("nxhello_main: 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("nxhello_main: Failed to get font handle: %d\n", errno);
+ g_nxhello.code = NXEXIT_FONTOPEN;
+ goto errout;
+ }
+
+ /* Set the background to the configured background color */
+
+ message("nxhello_main: 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("nxhello_main: 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_nxhellocb, NULL);
+ if (ret < 0)
+ {
+ message("nxhello_main: 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("nxhello_main: 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("nxhello_main: Close NX\n");
+ nx_close(g_nxhello.hnx);
+errout:
+ return g_nxhello.code;
+}
diff --git a/apps/examples/nximage/Kconfig b/apps/examples/nximage/Kconfig
new file mode 100644
index 000000000..e1d84a867
--- /dev/null
+++ b/apps/examples/nximage/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NXIMAGE
+ bool "NX graphics image example"
+ default n
+ ---help---
+ Enable the X graphics image example
+
+if EXAMPLES_NXIMAGE
+endif
diff --git a/apps/examples/nximage/Makefile b/apps/examples/nximage/Makefile
new file mode 100644
index 000000000..a59f05a79
--- /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 <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
+
+# 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 100644
index 000000000..eac0f5dc2
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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_nximagecb;
+
+/****************************************************************************
+ * 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..a7c304d31
--- /dev/null
+++ b/apps/examples/nximage/nximage_bitmap.c
@@ -0,0 +1,3711 @@
+/********************************************************************************************
+ * examples/nximage/nximage_bitmap.c
+ *
+ * Copyright (C) 2011-2012 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 <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
+ nrun >>= 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 100644
index 000000000..4a028f720
--- /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 <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 <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_nximagecb =
+{
+ 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 100644
index 000000000..729fcc53f
--- /dev/null
+++ b/apps/examples/nximage/nximage_main.c
@@ -0,0 +1,281 @@
+/****************************************************************************
+ * examples/nximage/nximage_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/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: nximage_main
+ *
+ * Description:
+ * Main entry pointer. Configures the basic display resources.
+ *
+ ****************************************************************************/
+
+int nximage_main(int argc, char *argv[])
+{
+ nxgl_mxpixel_t color;
+ int ret;
+
+ /* Initialize NX */
+
+ ret = nximage_initialize();
+ message("nximage_main: NX handle=%p\n", g_nximage.hnx);
+ if (!g_nximage.hnx || ret < 0)
+ {
+ message("nximage_main: 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("nximage_main: Set background color=%d\n", color);
+
+ ret = nx_setbgcolor(g_nximage.hnx, &color);
+ if (ret < 0)
+ {
+ message("nximage_main: 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_nximagecb, NULL);
+ if (ret < 0)
+ {
+ message("nximage_main: 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("nximage_main: 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("nximage_main: Close NX\n");
+ nx_close(g_nximage.hnx);
+errout:
+ return g_nximage.code;
+}
diff --git a/apps/examples/nxlines/Kconfig b/apps/examples/nxlines/Kconfig
new file mode 100644
index 000000000..5d18e00e0
--- /dev/null
+++ b/apps/examples/nxlines/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NXLINES
+ bool "NX graphics lines example"
+ default n
+ ---help---
+ Enable the X graphics lines example
+
+if EXAMPLES_NXLINES
+endif
diff --git a/apps/examples/nxlines/Makefile b/apps/examples/nxlines/Makefile
new file mode 100644
index 000000000..d6ddcf0b1
--- /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 <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
+
+# 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..a26db9f29
--- /dev/null
+++ b/apps/examples/nxlines/nxlines.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+ * examples/nxlines/nxlines.h
+ *
+ * Copyright (C) 2011-2012 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.
+ *
+ ****************************************************************************/
+
+#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_nxlinescb;
+
+/****************************************************************************
+ * 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..4c09519ed
--- /dev/null
+++ b/apps/examples/nxlines/nxlines_bkgd.c
@@ -0,0 +1,335 @@
+/****************************************************************************
+ * examples/nxlines/nxlines_bkgd.c
+ *
+ * Copyright (C) 2011-2012 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 <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_nxlinescb =
+{
+ 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, &center, 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, &center, 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..331fab631
--- /dev/null
+++ b/apps/examples/nxlines/nxlines_main.c
@@ -0,0 +1,272 @@
+/****************************************************************************
+ * examples/nxlines/nxlines_main.c
+ *
+ * Copyright (C) 2011-2012 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 <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: nxlines_main
+ ****************************************************************************/
+
+int nxlines_main(int argc, char *argv[])
+{
+ nxgl_mxpixel_t color;
+ int ret;
+
+ /* Initialize NX */
+
+ ret = nxlines_initialize();
+ message("nxlines_main: NX handle=%p\n", g_nxlines.hnx);
+ if (!g_nxlines.hnx || ret < 0)
+ {
+ message("nxlines_main: Failed to get NX handle: %d\n", errno);
+ g_nxlines.code = NXEXIT_NXOPEN;
+ goto errout;
+ }
+
+ /* Set the background to the configured background color */
+
+ message("nxlines_main: 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("nxlines_main: 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_nxlinescb, NULL);
+ if (ret < 0)
+ {
+ message("nxlines_main: 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("nxlines_main: 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("nxlines_main: Close NX\n");
+ nx_close(g_nxlines.hnx);
+errout:
+ return g_nxlines.code;
+}
diff --git a/apps/examples/nxtext/Kconfig b/apps/examples/nxtext/Kconfig
new file mode 100644
index 000000000..1ff2c44be
--- /dev/null
+++ b/apps/examples/nxtext/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_NXTEXT
+ bool "NX graphics text example"
+ default n
+ ---help---
+ Enable the NX graphics text example
+
+if EXAMPLES_NXTEXT
+endif
diff --git a/apps/examples/nxtext/Makefile b/apps/examples/nxtext/Makefile
new file mode 100644
index 000000000..8a9f349f4
--- /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 <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
+
+# 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..d457432db
--- /dev/null
+++ b/apps/examples/nxtext/nxtext_bkgd.c
@@ -0,0 +1,467 @@
+/****************************************************************************
+ * examples/nxtext/nxtext_bkgd.c
+ *
+ * Copyright (C) 2011-2012 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 <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_nxtextcb =
+{
+ 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..f0001e0bb
--- /dev/null
+++ b/apps/examples/nxtext/nxtext_internal.h
@@ -0,0 +1,366 @@
+/****************************************************************************
+ * examples/nxtext/nxtext_internal.h
+ *
+ * Copyright (C) 2011-2012 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.
+ *
+ ****************************************************************************/
+
+#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
+
+/* Pixel depth. If none provided, pick the smallest enabled pixel depth */
+
+#ifndef CONFIG_EXAMPLES_NXTEXT_BPP
+# if !defined(CONFIG_NX_DISABLE_1BPP)
+# define CONFIG_EXAMPLES_NXTEXT_BPP 1
+# elif !defined(CONFIG_NX_DISABLE_2BPP)
+# define CONFIG_EXAMPLES_NXTEXT_BPP 2
+# elif !defined(CONFIG_NX_DISABLE_4BPP)
+# define CONFIG_EXAMPLES_NXTEXT_BPP 4
+# elif !defined(CONFIG_NX_DISABLE_8BPP)
+# define CONFIG_EXAMPLES_NXTEXT_BPP 8
+# elif !defined(CONFIG_NX_DISABLE_16BPP)
+# define CONFIG_EXAMPLES_NXTEXT_BPP 16
+//#elif !defined(CONFIG_NX_DISABLE_24BPP)
+//# define CONFIG_NXCONSOLE_BPP 24
+# elif !defined(CONFIG_NX_DISABLE_32BPP)
+# define CONFIG_EXAMPLES_NXTEXT_BPP 32
+# else
+# error "No pixel depth provided"
+# endif
+#endif
+
+/* Background color */
+
+#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
+
+/* Pop-up font ID */
+
+#ifndef CONFIG_EXAMPLES_NXTEXT_PUFONTID
+# define CONFIG_EXAMPLES_NXTEXT_PUFONTID NXFONT_DEFAULT
+#endif
+
+/* Pop-up window color */
+
+#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
+
+/* Background font ID */
+
+#ifndef CONFIG_EXAMPLES_NXTEXT_BGFONTID
+# define CONFIG_EXAMPLES_NXTEXT_BGFONTID NXFONT_DEFAULT
+#endif
+
+/* Background font color */
+
+#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
+
+/* Pop-up font color */
+
+#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
+
+/* Character caching */
+
+#ifndef CONFIG_EXAMPLES_NXTEXT_BMCACHE
+# define CONFIG_EXAMPLES_NXTEXT_BMCACHE 128
+#endif
+
+/* Font glyph caching */
+
+#ifndef CONFIG_EXAMPLES_NXTEXT_GLCACHE
+# define CONFIG_EXAMPLES_NXTEXT_GLCACHE 16
+#endif
+
+/* NX muli-user mode */
+
+#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_nxtextcb;
+
+/* 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..9a4b8eea4
--- /dev/null
+++ b/apps/examples/nxtext/nxtext_main.c
@@ -0,0 +1,504 @@
+/****************************************************************************
+ * examples/nxtext/nxtext_main.c
+ *
+ * Copyright (C) 2011-2012 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 <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, &param);
+ 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, &param);
+ (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: nxtext_main
+ ****************************************************************************/
+
+int nxtext_main(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("nxtext_main: NX handle=%p\n", g_hnx);
+ if (!g_hnx || ret < 0)
+ {
+ message("nxtext_main: 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("nxtext_main: 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("nxtext_main: 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("nxtext_main: Set background color=%d\n", CONFIG_EXAMPLES_NXTEXT_BGCOLOR);
+ color = CONFIG_EXAMPLES_NXTEXT_BGCOLOR;
+ ret = nx_setbgcolor(g_hnx, &color);
+ if (ret < 0)
+ {
+ message("nxtext_main: 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_nxtextcb, bgstate);
+ if (ret < 0)
+ {
+ message("nxtext_main: 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("nxtext_main: 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("nxtext_main: Send keyboard input: %s\n", g_pumsg);
+ ret = nx_kbdin(g_hnx, strlen((FAR const char *)g_pumsg), g_pumsg);
+ if (ret < 0)
+ {
+ message("nxtext_main: 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("nxtext_main: 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("nxtext_main: 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("nxtext_main: Disconnect from the server\n");
+ nx_disconnect(g_hnx);
+#else
+ /* Close the server */
+
+ message("nxtext_main: 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..4faaf3a35
--- /dev/null
+++ b/apps/examples/nxtext/nxtext_popup.c
@@ -0,0 +1,408 @@
+/****************************************************************************
+ * examples/nxtext/nxtext_popup.c
+ *
+ * Copyright (C) 2011-2012 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 <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..13a441115
--- /dev/null
+++ b/apps/examples/nxtext/nxtext_putc.c
@@ -0,0 +1,598 @@
+/****************************************************************************
+ * examples/nxtext/nxtext_putc.c
+ *
+ * Copyright (C) 2011-2012 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 <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..a464628e1
--- /dev/null
+++ b/apps/examples/nxtext/nxtext_server.c
@@ -0,0 +1,194 @@
+/****************************************************************************
+ * examples/nxtext/nxtext_server.c
+ *
+ * Copyright (C) 2011-2012 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 <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/Kconfig b/apps/examples/ostest/Kconfig
new file mode 100644
index 000000000..0da7e4ce3
--- /dev/null
+++ b/apps/examples/ostest/Kconfig
@@ -0,0 +1,42 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_OSTEST
+ bool "OS test example"
+ default n
+ ---help---
+ Enable the OS test example
+
+if EXAMPLES_OSTEST
+
+config EXAMPLES_OSTEST_BUILTIN
+ bool "NSH built-in application"
+ default y if NSH_LIBRARY
+ default n if !NSH_LIBRARY
+ ---help---
+ Build the OS test example as an NSH built-in application.
+
+config EXAMPLES_OSTEST_LOOPS
+ int "OS test loop"
+ default 1
+ ---help---
+ 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
+ int "OS test stack size"
+ default 8192
+ ---help---
+ Size of the stack used to create the ostest task. Default is 8192.
+
+config EXAMPLES_OSTEST_NBARRIER_THREADS
+ int "Number of barrier threads"
+ default 8
+ ---help---
+ 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.
+
+endif
diff --git a/apps/examples/ostest/Makefile b/apps/examples/ostest/Makefile
new file mode 100644
index 000000000..374964b39
--- /dev/null
+++ b/apps/examples/ostest/Makefile
@@ -0,0 +1,149 @@
+############################################################################
+# apps/examples/ostest/Makefile
+#
+# Copyright (C) 2007-2012 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
+
+# ostest built-in application info
+
+APPNAME = ostest
+PRIORITY = SCHED_PRIORITY_DEFAULT
+STACKSIZE = 2048
+
+# NuttX OS Test
+
+ASRCS =
+CSRCS = ostest_main.c dev_null.c
+
+ifeq ($(CONFIG_ARCH_FPU),y)
+CSRCS += fpu.c
+endif
+
+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:
+ifeq ($(CONFIG_EXAMPLES_OSTEST_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/ostest/barrier.c b/apps/examples/ostest/barrier.c
new file mode 100644
index 000000000..e66496f7b
--- /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 <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 <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..11981d819
--- /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 <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 <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..96468c3e4
--- /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 <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 <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..34508d05e
--- /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 <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 <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/fpu.c b/apps/examples/ostest/fpu.c
new file mode 100644
index 000000000..89a1034ce
--- /dev/null
+++ b/apps/examples/ostest/fpu.c
@@ -0,0 +1,344 @@
+/***********************************************************************
+ * apps/examples/ostest/fpu.c
+ *
+ * Copyright (C) 2012 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/wait.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sched.h>
+
+#include "ostest.h"
+
+/***********************************************************************
+ * Pre-processor definitions
+ ***********************************************************************/
+/* Configuration *******************************************************/
+
+#undef HAVE_FPU
+#ifdef CONFIG_ARCH_FPU
+# if defined(CONFIG_EXAMPLES_OSTEST_FPUSIZE) && defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_DISABLE_SIGNALS)
+# define HAVE_FPU 1
+# else
+# ifndef CONFIG_EXAMPLES_OSTEST_FPUSIZE
+# warning "FPU test not built; CONFIG_EXAMPLES_OSTEST_FPUSIZE not defined"
+# endif
+# ifndef CONFIG_SCHED_WAITPID
+# warning "FPU test not built; CONFIG_SCHED_WAITPID not defined"
+# endif
+# ifdef CONFIG_DISABLE_SIGNALS
+# warning "FPU test not built; CONFIG_DISABLE_SIGNALS defined"
+# endif
+# endif
+#endif
+
+#ifdef HAVE_FPU
+
+#ifndef CONFIG_EXAMPLES_OSTEST_FPULOOPS
+# define CONFIG_EXAMPLES_OSTEST_FPULOOPS 16
+#endif
+
+#ifndef CONFIG_EXAMPLES_OSTEST_FPUMSDELAY
+# define CONFIG_EXAMPLES_OSTEST_FPUMSDELAY 750
+#endif
+
+#ifndef CONFIG_EXAMPLES_OSTEST_FPUPRIORITY
+# define CONFIG_EXAMPLES_OSTEST_FPUPRIORITY SCHED_PRIORITY_DEFAULT
+#endif
+
+#ifndef CONFIG_EXAMPLES_OSTEST_FPUSTACKSIZE
+# define CONFIG_EXAMPLES_OSTEST_FPUSTACKSIZE 2048
+#endif
+
+/* Other defintions ****************************************************/
+/* We'll keep all data using 32-bit values only to force 32-bit alignment.
+ * This logic has no real notion of the underlying representation.
+ */
+
+#define FPU_WORDSIZE ((CONFIG_EXAMPLES_OSTEST_FPUSIZE+3)>>2)
+#define FPU_NTHREADS 2
+
+#ifndef NULL
+# define NULL (void*)0
+#endif
+
+/***********************************************************************
+ * External Dependencies
+ ***********************************************************************/
+/* This test is very dependent on support provided by the chip/board-
+ * layer logic. In particular, it expects the following functions
+ * to be provided:
+ */
+
+/* Given an array of size CONFIG_EXAMPLES_OSTEST_FPUSIZE, this function
+ * will return the current FPU registers.
+ */
+
+extern void arch_getfpu(FAR uint32_t *fpusave);
+
+/* Given two arrays of size CONFIG_EXAMPLES_OSTEST_FPUSIZE this
+ * function will compare them and return true if they are identical.
+ */
+
+extern bool arch_cmpfpu(FAR const uint32_t *fpusave1,
+ FAR const uint32_t *fpusave2);
+
+/***********************************************************************
+ * Private Types
+ ***********************************************************************/
+
+struct fpu_threaddata_s
+{
+ uint32_t save1[FPU_WORDSIZE];
+ uint32_t save2[FPU_WORDSIZE];
+
+ /* These are just dummy values to force the compiler to do the
+ * requested floating point computations without the nonsense
+ * computations being optimized away.
+ */
+
+ volatile float sp1;
+ volatile float sp2;
+ volatile float sp3;
+ volatile float sp4;
+
+ volatile float dp1;
+ volatile float dp2;
+ volatile float dp3;
+ volatile float dp4;
+};
+
+/***********************************************************************
+ * Private Data
+ ***********************************************************************/
+
+static uint8_t g_fpuno;
+/* static */ struct fpu_threaddata_s g_fputhread[FPU_NTHREADS];
+
+/***********************************************************************
+ * Private Functions
+ ***********************************************************************/
+
+static void fpu_dump(FAR uint32_t *buffer, FAR const char *msg)
+{
+ int i, j, k;
+
+ printf("%s (%p):\n", msg, buffer);
+ for (i = 0; i < FPU_WORDSIZE; i += 8)
+ {
+ printf(" %04x: ", i);
+ for (j = 0; j < 8; j++)
+ {
+ k = i + j;
+
+ if (k < FPU_WORDSIZE)
+ {
+ printf("%08x ", buffer[k]);
+ }
+ else
+ {
+ printf("\n");
+ break;
+ }
+ }
+ printf("\n");
+ }
+}
+
+static int fpu_task(int argc, char *argv[])
+{
+ FAR struct fpu_threaddata_s *fpu;
+ register float sp1;
+ register float sp2;
+ register float sp3;
+ register float sp4;
+ register double dp1;
+ register double dp2;
+ register double dp3;
+ register double dp4;
+
+ int id;
+ int i;
+
+ /* Which are we? */
+
+ sched_lock();
+ fpu = &g_fputhread[g_fpuno];
+ id = (int)(++g_fpuno);
+ sched_unlock();
+
+ /* Seed the flowing point values */
+
+ sp1 = (float)id;
+ dp1 = (double)id;
+
+ for (i = 0; i < CONFIG_EXAMPLES_OSTEST_FPULOOPS; i++)
+ {
+ printf("FPU#%d: pass %d\n", id, i+1);
+ fflush(stdout);
+
+ /* Set the FPU register save arrays to a known-but-illogical values so
+ * that we can verify that reading of the registers actually occurs.
+ */
+
+ memset(fpu->save1, 0xff, FPU_WORDSIZE * sizeof(uint32_t));
+ memset(fpu->save2, 0xff, FPU_WORDSIZE * sizeof(uint32_t));
+
+ /* Prevent context switches while we set up some stuff */
+
+ sched_lock();
+
+ /* Do some trivial floating point operations that should cause some
+ * changes to floating point registers. First, some single preceision
+ * nonsense.
+ */
+
+ sp4 = (float)3.14159 * sp1; /* Multiple by Pi */
+ sp3 = sp4 + (float)1.61803; /* Add the golden ratio */
+ sp2 = sp3 / (float)2.71828; /* Divide by Euler's constant */
+ sp1 = sp2 + (float)1.0; /* Plus one */
+
+ fpu->sp1 = sp1; /* Make the compiler believe that somebody cares about the result */
+ fpu->sp2 = sp2;
+ fpu->sp3 = sp3;
+ fpu->sp4 = sp4;
+
+ /* Again using double precision */
+
+ dp4 = (double)3.14159 * dp1; /* Multiple by Pi */
+ dp3 = dp4 + (double)1.61803; /* Add the golden ratio */
+ dp2 = dp3 / (double)2.71828; /* Divide by Euler's constant */
+ dp1 = dp2 + (double)1.0; /* Plus one */
+
+ fpu->dp1 = dp1; /* Make the compiler believe that somebody cares about the result */
+ fpu->dp2 = dp2;
+ fpu->dp3 = dp3;
+ fpu->dp4 = dp4;
+
+ /* Sample the floating point registers */
+
+ arch_getfpu(fpu->save1);
+
+ /* Re-read and verify the FPU registers consistently without corruption */
+
+ arch_getfpu(fpu->save2);
+ if (!arch_cmpfpu(fpu->save1, fpu->save2))
+ {
+ printf("ERROR FPU#%d: save1 and save2 do not match\n", id);
+ fpu_dump(fpu->save1, "Values after math operations (save1)");
+ fpu_dump(fpu->save2, "Values after verify re-read (save2)");
+ return EXIT_FAILURE;
+ }
+
+ /* Now unlock and sleep for a while -- this should result in some context switches */
+
+ sched_unlock();
+ usleep(CONFIG_EXAMPLES_OSTEST_FPUMSDELAY * 1000);
+
+ /* Several context switches should have occurred. Now verify that the floating
+ * point registers are still correctly set.
+ */
+
+ arch_getfpu(fpu->save2);
+ if (!arch_cmpfpu(fpu->save1, fpu->save2))
+ {
+ printf("ERROR FPU#%d: save1 and save2 do not match\n", id);
+ fpu_dump(fpu->save1, "Values before waiting (save1)");
+ fpu_dump(fpu->save2, "Values after waiting (save2)");
+ return EXIT_FAILURE;
+ }
+ }
+
+ printf("FPU#%d: Succeeded\n", id);
+ fflush(stdout);
+ return EXIT_SUCCESS;
+}
+#endif /* HAVE_FPU */
+
+/***********************************************************************
+ * Private Functions
+ ***********************************************************************/
+
+void fpu_test(void)
+{
+#ifdef HAVE_FPU
+ pid_t task1;
+ pid_t task2;
+ int statloc;
+
+ /* Start two two tasks */
+
+ g_fpuno = 0;
+ printf("Starting task FPU#1\n");
+ task1 = TASK_CREATE("FPU#1", CONFIG_EXAMPLES_OSTEST_FPUPRIORITY, CONFIG_EXAMPLES_OSTEST_FPUSTACKSIZE, fpu_task, NULL);
+ if (task1 < 0)
+ {
+ printf("fpu_test: ERROR Failed to start task FPU#1\n");
+ }
+ else
+ {
+ printf("fpu_test: Started task FPU#1 at PID=%d\n", task1);
+ }
+ fflush(stdout);
+ usleep(250);
+
+ printf("Starting task FPU#2\n");
+ task2 = TASK_CREATE("FPU#2", CONFIG_EXAMPLES_OSTEST_FPUPRIORITY, CONFIG_EXAMPLES_OSTEST_FPUSTACKSIZE, fpu_task, NULL);
+ if (task2 < 0)
+ {
+ printf("fpu_test: ERROR Failed to start task FPU#1\n");
+ }
+ else
+ {
+ printf("fpu_test: Started task FPU#2 at PID=%d\n", task2);
+ }
+
+ /* Wait for each task to complete */
+
+ fflush(stdout);
+ (void)waitpid(task1, &statloc, 0);
+ (void)waitpid(task2, &statloc, 0);
+
+#else
+ printf("fpu_test: ERROR: The FPU test is not properly configured\n");
+#endif
+ printf("fpu_test: Returning\n");
+}
diff --git a/apps/examples/ostest/mqueue.c b/apps/examples/ostest/mqueue.c
new file mode 100644
index 000000000..39ef76a53
--- /dev/null
+++ b/apps/examples/ostest/mqueue.c
@@ -0,0 +1,394 @@
+/**************************************************************************
+ * apps/examples/ostest/mqueue.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 <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");
+ }
+ }
+ 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..0b7f70daa
--- /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 <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 <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..a4af37f05
--- /dev/null
+++ b/apps/examples/ostest/ostest.h
@@ -0,0 +1,178 @@
+/****************************************************************************
+ * apps/examples/ostest/ostest.h
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_EXAMPLES_OSTEST_OSTEST_H
+#define __APPS_EXAMPLES_OSTEST_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);
+
+/* fpu.c ********************************************************************/
+
+extern void fpu_test(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 /* __APPS_EXAMPLES_OSTEST_OSTEST_H */
diff --git a/apps/examples/ostest/ostest_main.c b/apps/examples/ostest/ostest_main.c
new file mode 100644
index 000000000..46726d515
--- /dev/null
+++ b/apps/examples/ostest/ostest_main.c
@@ -0,0 +1,522 @@
+/****************************************************************************
+ * apps/examples/ostest/ostest_main.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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 <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
+
+#ifdef CONFIG_ARCH_FPU
+ /* Check that the FPU is properly supported during context switching */
+
+ printf("\nuser_main: FPU test\n");
+ fpu_test();
+ 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 ostest_main 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
+ ****************************************************************************/
+
+/****************************************************************************
+ * ostest_main
+ ****************************************************************************/
+
+int ostest_main(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("ostest_main: putenv(%s)\n", g_putenv_value);
+ putenv(g_putenv_value); /* Varaible1=BadValue3 */
+ printf("ostest_main: setenv(%s, %s, TRUE)\n", g_var1_name, g_var1_value);
+ setenv(g_var1_name, g_var1_value, TRUE); /* Variable1=GoodValue1 */
+
+ printf("ostest_main: setenv(%s, %s, FALSE)\n", g_var2_name, g_bad_value1);
+ setenv(g_var2_name, g_bad_value1, FALSE); /* Variable2=BadValue1 */
+ printf("ostest_main: setenv(%s, %s, TRUE)\n", g_var2_name, g_var2_value);
+ setenv(g_var2_name, g_var2_value, TRUE); /* Variable2=GoodValue2 */
+
+ printf("ostest_main: setenv(%s, %s, FALSE)\n", g_var3_name, g_var3_name);
+ setenv(g_var3_name, g_var3_value, FALSE); /* Variable3=GoodValue3 */
+ printf("ostest_main: 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("ostest_main: ERROR Failed to start user_main\n");
+ }
+ else
+ {
+ printf("ostest_main: Started user_main at PID=%d\n", result);
+ }
+
+ printf("ostest_main: Exitting\n");
+ return 0;
+}
diff --git a/apps/examples/ostest/posixtimer.c b/apps/examples/ostest/posixtimer.c
new file mode 100644
index 000000000..ebb1ab79e
--- /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 <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 <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, &notify, &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..cd04df7e6
--- /dev/null
+++ b/apps/examples/ostest/prioinherit.c
@@ -0,0 +1,559 @@
+/****************************************************************************
+ * examples/ostest/prioinherit.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 NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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
+
+/* If resources were configured for lots of holders, then run 3 low priority
+ * threads. Otherwise, just one.
+ */
+
+#if CONFIG_SEM_PREALLOCHOLDERS > 3
+# define NLOWPRI_THREADS 3
+#else
+# define NLOWPRI_THREADS 1
+#endif
+
+#ifndef CONFIG_SEM_NNESTPRIO
+# define CONFIG_SEM_NNESTPRIO 0
+#endif
+
+/* Where resources configured for lots of waiters? If so then run 3 high
+ * priority threads. Otherwise, just one.
+ */
+
+#if CONFIG_SEM_NNESTPRIO > 3
+# define NHIGHPRI_THREADS 3
+#else
+# define NHIGHPRI_THREADS 1
+#endif
+
+/****************************************************************************
+ * 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..ffd99c2df
--- /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 <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 <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..5167a857e
--- /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 <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 <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..48be57a85
--- /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 <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 <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..eabfe5646
--- /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 <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 <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, &param);
+ 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..6c3269e84
--- /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 <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 <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..7cf875fb6
--- /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 <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 <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/Kconfig b/apps/examples/pashello/Kconfig
new file mode 100644
index 000000000..5591d6b5b
--- /dev/null
+++ b/apps/examples/pashello/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_PASHELLO
+ bool "Pascal \"Hello, World!\" example"
+ default n
+ ---help---
+ Enable the Pascal \"Hello, World!\" example
+
+if EXAMPLES_PASHELLO
+endif
diff --git a/apps/examples/pashello/Makefile b/apps/examples/pashello/Makefile
new file mode 100644
index 000000000..f090a68ea
--- /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 <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
+
+# 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..b19846966
--- /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 pseudo filesystem.
+
diff --git a/apps/examples/pashello/device.c b/apps/examples/pashello/device.c
new file mode 100644
index 000000000..a3950e6a3
--- /dev/null
+++ b/apps/examples/pashello/device.c
@@ -0,0 +1,110 @@
+/****************************************************************************
+ * examples/pashello/device.c
+ *
+ * Copyright (C) 2008, 2012 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Compilation Switches
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+#include <nuttx/fs/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
new file mode 100644
index 000000000..c23610598
--- /dev/null
+++ b/apps/examples/pashello/hello.pex
Binary files differ
diff --git a/apps/examples/pashello/mkhello.sh b/apps/examples/pashello/mkhello.sh
new file mode 100755
index 000000000..e8f196498
--- /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 <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.
+#
+############################################################################
+#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..b8c19b6a4
--- /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 <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 <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
+ ****************************************************************************/
+
+/****************************************************************************
+ * pashello_main
+ ****************************************************************************/
+
+int pashello_main(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, "pashello_main: ERROR: Could not load /dev/hello\n");
+ exit(1);
+ }
+ printf("pashello_main: /dev/hello Loaded\n");
+ printf("pashello_main: Interpreter started:\n");
+
+ /* And start program execution */
+
+ prun(st);
+
+ /* Clean up resources used by the interpreter */
+
+ printf("pashello_main: 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..ac5f99fbe
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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/Kconfig b/apps/examples/pipe/Kconfig
new file mode 100644
index 000000000..26bc92fcc
--- /dev/null
+++ b/apps/examples/pipe/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_PIPE
+ bool "Pipe example"
+ default n
+ ---help---
+ Enable the pipe example
+
+if EXAMPLES_PIPE
+endif
diff --git a/apps/examples/pipe/Makefile b/apps/examples/pipe/Makefile
new file mode 100644
index 000000000..956c911b3
--- /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 <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
+
+# 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..20d4113eb
--- /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 <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/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..38143e492
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..63a4f283f
--- /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 <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/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: pipe_main
+ ****************************************************************************/
+
+int pipe_main(int argc, char *argv[])
+{
+ int filedes[2];
+ int ret;
+
+ /* Test FIFO logic */
+
+ printf("\npipe_main: Performing FIFO test\n");
+ ret = mkfifo(FIFO_PATH1, 0666);
+ if (ret < 0)
+ {
+ fprintf(stderr, "pipe_main: 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, "pipe_main: 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, "pipe_main: Failed to open FIFO %s for reading, errno=%d\n",
+ FIFO_PATH1, errno);
+ if (close(filedes[1]) != 0)
+ {
+ fprintf(stderr, "pipe_main: 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, "pipe_main: close failed: %d\n", errno);
+ }
+ if (close(filedes[1]) != 0)
+ {
+ fprintf(stderr, "pipe_main: close failed: %d\n", errno);
+ }
+ /* unlink(FIFO_PATH1); fails */
+
+ if (ret != 0)
+ {
+ fprintf(stderr, "pipe_main: FIFO test FAILED (%d)\n", ret);
+ return 4;
+ }
+ printf("pipe_main: FIFO test PASSED\n");
+
+ /* Test PIPE logic */
+
+ printf("\npipe_main: Performing pipe test\n");
+ ret = pipe(filedes);
+ if (ret < 0)
+ {
+ fprintf(stderr, "pipe_main: 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, "pipe_main: close failed: %d\n", errno);
+ }
+ if (close(filedes[1]) != 0)
+ {
+ fprintf(stderr, "pipe_main: close failed: %d\n", errno);
+ }
+
+ if (ret != 0)
+ {
+ fprintf(stderr, "pipe_main: PIPE test FAILED (%d)\n", ret);
+ return 6;
+ }
+ printf("pipe_main: PIPE test PASSED\n");
+
+ /* Perform the FIFO interlock test */
+
+ printf("\npipe_main: Performing pipe interlock test\n");
+ ret = interlock_test();
+ if (ret != 0)
+ {
+ fprintf(stderr, "pipe_main: FIFO interlock test FAILED (%d)\n", ret);
+ return 7;
+ }
+ printf("pipe_main: PIPE interlock test PASSED\n");
+
+ /* Perform the pipe redirection test */
+
+ printf("\npipe_main: Performing redirection test\n");
+ ret = redirection_test();
+ if (ret != 0)
+ {
+ fprintf(stderr, "pipe_main: FIFO redirection test FAILED (%d)\n", ret);
+ return 7;
+ }
+ printf("pipe_main: 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..26fe9bcaa
--- /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 <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 <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, "pipe_main: close failed: %d\n", errno);
+ }
+ if (close(filedes[1]) != 0)
+ {
+ fprintf(stderr, "pipe_main: close failed: %d\n", errno);
+ }
+
+ if (ret != 0)
+ {
+ fprintf(stderr, "pipe_main: 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..f7c612881
--- /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 <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 <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/Kconfig b/apps/examples/poll/Kconfig
new file mode 100644
index 000000000..c52827496
--- /dev/null
+++ b/apps/examples/poll/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_POLL
+ bool "Poll example"
+ default n
+ ---help---
+ Enable the poll example
+
+if EXAMPLES_POLL
+endif
diff --git a/apps/examples/poll/Makefile b/apps/examples/poll/Makefile
new file mode 100644
index 000000000..aef61d199
--- /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 <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
+
+# 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..1e6a72089
--- /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 <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.
+#
+############################################################################
+
+# 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..302cceb0f
--- /dev/null
+++ b/apps/examples/poll/host.c
@@ -0,0 +1,171 @@
+/****************************************************************************
+ * examples/poll/host.c
+ *
+ * Copyright (C) 2008-2009, 2012 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 <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;
+ }
+ else if (nbytesrecvd == 0)
+ {
+ message("client: The server broke the connections\n");
+ 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..81ad7cdcc
--- /dev/null
+++ b/apps/examples/poll/net_listener.c
@@ -0,0 +1,428 @@
+/****************************************************************************
+ * examples/poll/net_listener.c
+ *
+ * Copyright (C) 2008-2009, 2011-2012 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/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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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..8a13618c3
--- /dev/null
+++ b/apps/examples/poll/net_reader.c
@@ -0,0 +1,317 @@
+/****************************************************************************
+ * examples/poll/net_reader.c
+ *
+ * Copyright (C) 2008-2009, 2011-2012 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 <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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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..b2400932e
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..fe1c95089
--- /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 <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 <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..0c475fa7a
--- /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 <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 <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: poll_main
+ ****************************************************************************/
+
+int poll_main(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("\npoll_main: Creating FIFO %s\n", FIFO_PATH1);
+ ret = mkfifo(FIFO_PATH1, 0666);
+ if (ret < 0)
+ {
+ message("poll_main: mkfifo failed: %d\n", errno);
+ exitcode = 1;
+ goto errout;
+ }
+
+ message("\npoll_main: Creating FIFO %s\n", FIFO_PATH2);
+ ret = mkfifo(FIFO_PATH2, 0666);
+ if (ret < 0)
+ {
+ message("poll_main: 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("poll_main: 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("poll_main: Failed to open FIFO %s for writing, errno=%d\n",
+ FIFO_PATH2, errno);
+ exitcode = 4;
+ goto errout;
+ }
+
+ /* Start the listeners */
+
+ message("poll_main: Starting poll_listener thread\n");
+
+ ret = pthread_create(&tid1, NULL, poll_listener, NULL);
+ if (ret != 0)
+ {
+ message("poll_main: Failed to create poll_listener thread: %d\n", ret);
+ exitcode = 5;
+ goto errout;
+ }
+
+ message("poll_main: Starting select_listener thread\n");
+
+ ret = pthread_create(&tid2, NULL, select_listener, NULL);
+ if (ret != 0)
+ {
+ message("poll_main: Failed to create select_listener thread: %d\n", ret);
+ exitcode = 6;
+ goto errout;
+ }
+
+#ifdef HAVE_NETPOLL
+#ifdef CONFIG_NET_TCPBACKLOG
+ message("poll_main: Starting net_listener thread\n");
+
+ ret = pthread_create(&tid3, NULL, net_listener, NULL);
+#else
+ message("poll_main: Starting net_reader thread\n");
+
+ ret = pthread_create(&tid3, NULL, net_reader, NULL);
+#endif
+ if (ret != 0)
+ {
+ message("poll_main: 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("poll_main: Write to fd1 failed: %d\n", errno);
+ exitcode = 7;
+ goto errout;
+ }
+
+ nbytes = write(fd2, buffer, strlen(buffer));
+ if (nbytes < 0)
+ {
+ message("poll_main: Write fd2 failed: %d\n", errno);
+ exitcode = 8;
+ goto errout;
+ }
+
+ message("\npoll_main: 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..5cb7e7805
--- /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 <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 <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/pwm/Kconfig b/apps/examples/pwm/Kconfig
new file mode 100644
index 000000000..78edd2178
--- /dev/null
+++ b/apps/examples/pwm/Kconfig
@@ -0,0 +1,48 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_PWM
+ bool "Pulse width modulation (PWM) example"
+ default n
+ depends on PWM && NSH_BUILTIN_APPS
+ ---help---
+ Enable the Pulse width modulation (PWM) example
+
+if EXAMPLES_PWM
+
+config EXAMPLES_PWM_DEVPATH
+ string "PWM device path"
+ default "/dev/pwm0"
+ ---help---
+ The path to the PWM device. Default: /dev/pwm0
+
+config EXAMPLES_PWM_FREQUENCY
+ int "Default PWM freququency"
+ default 100
+ ---help---
+ The default PWM frequency. Default: 100 Hz
+
+config EXAMPLES_PWM_DUTYPCT
+ int "Default PWM duty percentage"
+ default 50
+ ---help---
+ The default PWM duty as a percentage. Default: 50%
+
+config EXAMPLES_PWM_DURATION
+ int "Default PWM duration"
+ default 5 if !EXAMPLES_PWM_PULSECOUNT
+ ---help---
+ The default PWM pulse train duration in seconds. Used only if the current
+ pulse count is zero (pulse countis only supported if CONFIG_PWM_PULSECOUNT
+ is defined). Default: 5 seconds
+
+config EXAMPLES_PWM_PULSECOUNT
+ int "Default pulse count"
+ default 0
+ ---help---
+ The initial PWM pulse count. This option is only available if CONFIG_PWM_PULSECOUNT
+ is nonzero. Default: 0 (i.e., use the duration, not the count).
+
+endif
diff --git a/apps/examples/pwm/Makefile b/apps/examples/pwm/Makefile
new file mode 100644
index 000000000..efbdb048e
--- /dev/null
+++ b/apps/examples/pwm/Makefile
@@ -0,0 +1,103 @@
+############################################################################
+# apps/examples/pwm/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
+
+# PWM Example.
+
+ASRCS =
+CSRCS = pwm_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 .
+
+# PWM built-in application info
+
+APPNAME = pwm
+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:
+ $(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/examples/pwm/pwm.h b/apps/examples/pwm/pwm.h
new file mode 100644
index 000000000..5c049a8f8
--- /dev/null
+++ b/apps/examples/pwm/pwm.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+ * examples/examples/pwm/pwm.h
+ *
+ * Copyright (C) 2011-2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_EXAMPLES_PWM_PWM_H
+#define __APPS_EXAMPLES_PWM_PWM_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* CONFIG_NSH_BUILTIN_APPS - Build the PWM test as an NSH built-in function.
+ * Default: Not built! The example can only be used as an NSH built-in
+ * application
+ * CONFIG_EXAMPLES_PWM_DEVPATH - The path to the PWM device. Default: /dev/pwm0
+ * CONFIG_EXAMPLES_PWM_FREQUENCY - The initial PWM frequency. Default: 100 Hz
+ * CONFIG_EXAMPLES_PWM_DUTYPCT - The initial PWM duty as a percentage. Default: 50%
+ * CONFIG_EXAMPLES_PWM_DURATION - The initial PWM pulse train duration in seconds.
+ * Used only if the current pulse count is zero (pulse count is only supported
+ * if CONFIG_PWM_PULSECOUNT is defined). Default: 5 seconds
+ * CONFIG_EXAMPLES_PWM_PULSECOUNT - The initial PWM pulse count. This option is
+ * only available if CONFIG_PWM_PULSECOUNT is defined. Default: 0 (i.e., use
+ * the duration, not the count).
+ */
+
+#ifndef CONFIG_PWM
+# error "PWM device support is not enabled (CONFIG_PWM)"
+#endif
+
+#ifndef CONFIG_NSH_BUILTIN_APPS
+# warning "The PWM example only works as an NSH built-in application (CONFIG_NSH_BUILTIN_APPS)"
+#endif
+
+#ifndef CONFIG_EXAMPLES_PWM_DEVPATH
+# define CONFIG_EXAMPLES_PWM_DEVPATH "/dev/pwm0"
+#endif
+
+#ifndef CONFIG_EXAMPLES_PWM_FREQUENCY
+# define CONFIG_EXAMPLES_PWM_FREQUENCY 100
+#endif
+
+#ifndef CONFIG_EXAMPLES_PWM_DUTYPCT
+# define CONFIG_EXAMPLES_PWM_DUTYPCT 50
+#endif
+
+#ifndef CONFIG_EXAMPLES_PWM_DURATION
+# define CONFIG_EXAMPLES_PWM_DURATION 5
+#endif
+
+#ifndef CONFIG_EXAMPLES_PWM_COUNT
+# define CONFIG_EXAMPLES_PWM_COUNT 0
+#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: pwm_devinit()
+ *
+ * Description:
+ * Perform architecuture-specific initialization of the PWM hardware. This
+ * interface must be provided by all configurations using apps/examples/pwm
+ *
+ ****************************************************************************/
+
+int pwm_devinit(void);
+
+#endif /* __APPS_EXAMPLES_PWM_PWM_H */
diff --git a/apps/examples/pwm/pwm_main.c b/apps/examples/pwm/pwm_main.c
new file mode 100644
index 000000000..775bdba6b
--- /dev/null
+++ b/apps/examples/pwm/pwm_main.c
@@ -0,0 +1,394 @@
+/****************************************************************************
+ * examples/pwm/pwm_main.c
+ *
+ * Copyright (C) 2011-2012 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 <sys/ioctl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/pwm.h>
+
+#include "pwm.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct pwm_state_s
+{
+ bool initialized;
+ FAR char *devpath;
+ uint8_t duty;
+ uint32_t freq;
+#ifdef CONFIG_PWM_PULSECOUNT
+ uint32_t count;
+#endif
+ int duration;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct pwm_state_s g_pwmstate;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pwm_devpath
+ ****************************************************************************/
+
+static void pwm_devpath(FAR struct pwm_state_s *pwm, FAR const char *devpath)
+{
+ /* Get rid of any old device path */
+
+ if (pwm->devpath)
+ {
+ free(pwm->devpath);
+ }
+
+ /* Then set-up the new device path by copying the string */
+
+ pwm->devpath = strdup(devpath);
+}
+
+/****************************************************************************
+ * Name: pwm_help
+ ****************************************************************************/
+
+static void pwm_help(FAR struct pwm_state_s *pwm)
+{
+ message("Usage: pwm [OPTIONS]\n");
+ message("\nArguments are \"sticky\". For example, once the PWM frequency is\n");
+ message("specified, that frequency will be re-used until it is changed.\n");
+ message("\n\"sticky\" OPTIONS include:\n");
+ message(" [-p devpath] selects the PWM device. "
+ "Default: %s Current: %s\n",
+ CONFIG_EXAMPLES_PWM_DEVPATH, pwm->devpath ? pwm->devpath : "NONE");
+ message(" [-f addr] selects the pulse frequency. "
+ "Default: %d Hz Current: %d Hz\n",
+ CONFIG_EXAMPLES_PWM_FREQUENCY, pwm->freq);
+ message(" [-d duty] selcts the pulse duty as a percentage. "
+ "Default: %d %% Current: %d %%\n",
+ CONFIG_EXAMPLES_PWM_DUTYPCT, pwm->duty);
+#ifdef CONFIG_PWM_PULSECOUNT
+ message(" [-n count] selects the pulse count. "
+ "Default: %d Current: %d\n",
+ CONFIG_EXAMPLES_PWM_COUNT, pwm->count);
+#endif
+ message(" [-t duration] is the duration of the pulse train in seconds. "
+ "Default: %d Current: %d\n",
+ CONFIG_EXAMPLES_PWM_DURATION, pwm->duration);
+ message(" [-h] shows this message and exits\n");
+}
+
+/****************************************************************************
+ * Name: arg_string
+ ****************************************************************************/
+
+static 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
+ ****************************************************************************/
+
+static 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: parse_args
+ ****************************************************************************/
+
+static void parse_args(FAR struct pwm_state_s *pwm, int argc, FAR char **argv)
+{
+ FAR char *ptr;
+ FAR char *str;
+ long value;
+ int index;
+ int nargs;
+
+ for (index = 1; index < argc; )
+ {
+ ptr = argv[index];
+ if (ptr[0] != '-')
+ {
+ message("Invalid options format: %s\n", ptr);
+ exit(0);
+ }
+
+ switch (ptr[1])
+ {
+ case 'f':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 1)
+ {
+ message("Frequency out of range: %ld\n", value);
+ exit(1);
+ }
+
+ pwm->freq = (uint32_t)value;
+ index += nargs;
+ break;
+
+ case 'd':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 1 || value > 99)
+ {
+ message("Duty out of range: %ld\n", value);
+ exit(1);
+ }
+
+ pwm->duty = (uint8_t)value;
+ index += nargs;
+ break;
+
+#ifdef CONFIG_PWM_PULSECOUNT
+ case 'n':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 0)
+ {
+ message("Count must be non-negative: %ld\n", value);
+ exit(1);
+ }
+
+ pwm->count = (uint32_t)value;
+ index += nargs;
+ break;
+
+#endif
+ case 'p':
+ nargs = arg_string(&argv[index], &str);
+ pwm_devpath(pwm, str);
+ index += nargs;
+ break;
+
+ case 't':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 1 || value > INT_MAX)
+ {
+ message("Duration out of range: %ld\n", value);
+ exit(1);
+ }
+
+ pwm->duration = (int)value;
+ index += nargs;
+ break;
+
+ case 'h':
+ pwm_help(pwm);
+ exit(0);
+
+ default:
+ message("Unsupported option: %s\n", ptr);
+ pwm_help(pwm);
+ exit(1);
+ }
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pwm_main
+ ****************************************************************************/
+
+int pwm_main(int argc, char *argv[])
+{
+ struct pwm_info_s info;
+ int fd;
+ int ret;
+
+ /* Initialize the state data */
+
+ if (!g_pwmstate.initialized)
+ {
+ g_pwmstate.duty = CONFIG_EXAMPLES_PWM_DUTYPCT;
+ g_pwmstate.freq = CONFIG_EXAMPLES_PWM_FREQUENCY;
+ g_pwmstate.duration = CONFIG_EXAMPLES_PWM_DURATION;
+#ifdef CONFIG_PWM_PULSECOUNT
+ g_pwmstate.count = CONFIG_EXAMPLES_PWM_COUNT;
+#endif
+ g_pwmstate.initialized = true;
+ }
+
+ /* Parse the command line */
+
+ parse_args(&g_pwmstate, argc, argv);
+
+ /* Has a device been assigned? */
+
+ if (!g_pwmstate.devpath)
+ {
+ /* No.. use the default device */
+
+ pwm_devpath(&g_pwmstate, CONFIG_EXAMPLES_PWM_DEVPATH);
+ }
+
+ /* Initialization of the PWM hardware is performed by logic external to
+ * this test.
+ */
+
+ ret = pwm_devinit();
+ if (ret != OK)
+ {
+ message("pwm_main: pwm_devinit failed: %d\n", ret);
+ goto errout;
+ }
+
+ /* Open the PWM device for reading */
+
+ fd = open(g_pwmstate.devpath, O_RDONLY);
+ if (fd < 0)
+ {
+ message("pwm_main: open %s failed: %d\n", g_pwmstate.devpath, errno);
+ goto errout;
+ }
+
+ /* Configure the characteristics of the pulse train */
+
+ info.frequency = g_pwmstate.freq;
+ info.duty = ((uint32_t)g_pwmstate.duty << 16) / 100;
+#ifdef CONFIG_PWM_PULSECOUNT
+ info.count = g_pwmstate.count;
+
+ message("pwm_main: starting output with frequency: %d duty: %08x count: %d\n",
+ info.frequency, info.duty, info.count);
+
+#else
+ message("pwm_main: starting output with frequency: %d duty: %08x\n",
+ info.frequency, info.duty);
+
+#endif
+
+ ret = ioctl(fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&info));
+ if (ret < 0)
+ {
+ message("pwm_main: ioctl(PWMIOC_SETCHARACTERISTICS) failed: %d\n", errno);
+ goto errout_with_dev;
+ }
+
+ /* Then start the pulse train. Since the driver was opened in blocking
+ * mode, this call will block if the count value is greater than zero.
+ */
+
+ ret = ioctl(fd, PWMIOC_START, 0);
+ if (ret < 0)
+ {
+ message("pwm_main: ioctl(PWMIOC_START) failed: %d\n", errno);
+ goto errout_with_dev;
+ }
+
+ /* It a non-zero count was not specified, then wait for the selected
+ * duration, then stop the PWM output.
+ */
+
+#ifdef CONFIG_PWM_PULSECOUNT
+ if (info.count == 0)
+#endif
+ {
+ /* Wait for the specified duration */
+
+ sleep(g_pwmstate.duration);
+
+ /* Then stop the pulse train */
+
+ message("pwm_main: stopping output\n", info.frequency, info.duty);
+
+ ret = ioctl(fd, PWMIOC_STOP, 0);
+ if (ret < 0)
+ {
+ message("pwm_main: ioctl(PWMIOC_STOP) failed: %d\n", errno);
+ goto errout_with_dev;
+ }
+ }
+
+ close(fd);
+ msgflush();
+ return OK;
+
+errout_with_dev:
+ close(fd);
+errout:
+ msgflush();
+ return ERROR;
+}
diff --git a/apps/examples/qencoder/Kconfig b/apps/examples/qencoder/Kconfig
new file mode 100644
index 000000000..e0026d08c
--- /dev/null
+++ b/apps/examples/qencoder/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_QENCODER
+ bool "Quadrature encoder example"
+ default n
+ ---help---
+ Enable the quadrature encoder example
+
+if EXAMPLES_QENCODER
+endif
diff --git a/apps/examples/qencoder/Makefile b/apps/examples/qencoder/Makefile
new file mode 100644
index 000000000..3f3fc9def
--- /dev/null
+++ b/apps/examples/qencoder/Makefile
@@ -0,0 +1,105 @@
+############################################################################
+# apps/examples/qe/Makefile
+#
+# Copyright (C) 2012 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
+
+# NuttX NX Graphics Example.
+
+ASRCS =
+CSRCS = qe_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 .
+
+# Quadrature Encoder built-in application info
+
+APPNAME = qe
+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/qencoder/qe.h b/apps/examples/qencoder/qe.h
new file mode 100644
index 000000000..4c03689ab
--- /dev/null
+++ b/apps/examples/qencoder/qe.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+ * examples/examples/qe/qe.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_EXAMPLES_QENCODER_QE_H
+#define __APPS_EXAMPLES_QENCODER_QE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* CONFIG_NSH_BUILTIN_APPS - Build the QE test as an NSH built-in function.
+ * Default: Built as a standalone problem
+ * CONFIG_EXAMPLES_QENCODER_DEVPATH - The path to the QE device. Default:
+ * /dev/qe0
+ * CONFIG_EXAMPLES_QENCODER_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_QENCODER_DELAY - This value provides the delay (in
+ * milliseonds) between each sample. If CONFIG_NSH_BUILTIN_APPS
+ * is defined, then this value is the default delay if no other delay is
+ * provided on the command line. Default: 100 milliseconds
+ */
+
+#ifndef CONFIG_QENCODER
+# error "QE device support is not enabled (CONFIG_QENCODER)"
+#endif
+
+#ifndef CONFIG_EXAMPLES_QENCODER_DEVPATH
+# define CONFIG_EXAMPLES_QENCODER_DEVPATH "/dev/qe0"
+#endif
+
+#ifndef CONFIG_EXAMPLES_QENCODER_DELAY
+# define CONFIG_EXAMPLES_QENCODER_DELAY 100
+#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
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+struct qe_example_s
+{
+ bool initialized; /* True: QE devices have been initialized */
+ bool reset; /* True: set the count back to zero */
+ FAR char *devpath; /* Path to the QE device */
+ unsigned int nloops; /* Collect this number of samples */
+ unsigned int delay; /* Delay this number of seconds between samples */
+};
+#endif
+
+/****************************************************************************
+ * Public Variables
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+extern struct qe_example_s g_qeexample;
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: qe_devinit()
+ *
+ * Description:
+ * Perform architecuture-specific initialization of the QE hardware. This
+ * interface must be provided by all configurations using apps/examples/qe
+ *
+ ****************************************************************************/
+
+int qe_devinit(void);
+
+#endif /* __APPS_EXAMPLES_QENCODER_QE_H */
diff --git a/apps/examples/qencoder/qe_main.c b/apps/examples/qencoder/qe_main.c
new file mode 100644
index 000000000..8c185ea1b
--- /dev/null
+++ b/apps/examples/qencoder/qe_main.c
@@ -0,0 +1,362 @@
+/****************************************************************************
+ * examples/qe/qe_main.c
+ *
+ * Copyright (C) 2012 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 <sys/ioctl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/sensors/qencoder.h>
+
+#include "qe.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+struct qe_example_s g_qeexample;
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: qe_devpath
+ ****************************************************************************/
+
+static void qe_devpath(FAR const char *devpath)
+{
+ /* Get rid of any old device path */
+
+ if (g_qeexample.devpath)
+ {
+ free(g_qeexample.devpath);
+ }
+
+ /* The set-up the new device path by copying the string */
+
+ g_qeexample.devpath = strdup(devpath);
+}
+
+/****************************************************************************
+ * Name: qe_help
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+static void qe_help(void)
+{
+ message("\nUsage: qe [OPTIONS]\n\n");
+ message("OPTIONS include:\n");
+ message(" [-p devpath] QE device path\n");
+ message(" [-n samples] Number of samples\n");
+ message(" [-t msec] Delay between samples (msec)\n");
+ message(" [-r] Reset the position to zero\n");
+ message(" [-h] Shows this message and exits\n\n");
+}
+#endif
+
+/****************************************************************************
+ * Name: arg_string
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+static 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;
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: arg_decimal
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+static 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;
+}
+#endif
+
+/****************************************************************************
+ * Name: parse_args
+ ****************************************************************************/
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+static void parse_args(int argc, FAR char **argv)
+{
+ FAR char *ptr;
+ FAR char *str;
+ long value;
+ int index;
+ int nargs;
+
+ g_qeexample.reset = false;
+ g_qeexample.nloops = 1;
+ g_qeexample.delay = CONFIG_EXAMPLES_QENCODER_DELAY;
+
+ for (index = 1; index < argc; )
+ {
+ ptr = argv[index];
+ if (ptr[0] != '-')
+ {
+ message("Invalid options format: %s\n", ptr);
+ exit(0);
+ }
+
+ switch (ptr[1])
+ {
+ case 'n':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 0 || value > INT_MAX)
+ {
+ message("Sample count out of range: %ld\n", value);
+ exit(1);
+ }
+
+ g_qeexample.nloops = (unsigned int)value;
+ index += nargs;
+ break;
+
+ case 'p':
+ nargs = arg_string(&argv[index], &str);
+ qe_devpath(str);
+ index += nargs;
+ break;
+
+ case 't':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 0 || value > INT_MAX)
+ {
+ message("Sample delay out of range: %ld\n", value);
+ exit(1);
+ }
+
+ g_qeexample.delay = (unsigned int)value;
+ index += nargs;
+ break;
+
+ case 'r':
+ g_qeexample.reset = true;
+ index++;
+ break;
+
+ case 'h':
+ qe_help();
+ exit(EXIT_SUCCESS);
+
+ default:
+ message("Unsupported option: %s\n", ptr);
+ qe_help();
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: qe_main
+ ****************************************************************************/
+
+int qe_main(int argc, char *argv[])
+{
+ int32_t position;
+ int fd;
+ int exitval = EXIT_SUCCESS;
+ int ret;
+#if defined(CONFIG_NSH_BUILTIN_APPS) || defined(CONFIG_EXAMPLES_QENCODER_NSAMPLES)
+ int nloops;
+#endif
+
+ /* Check if we have initialized */
+
+ if (!g_qeexample.initialized)
+ {
+ /* Initialization of the encoder hardware is performed by logic external to
+ * this test.
+ */
+
+ message("qe_main: Initializing external encoder(s)\n");
+ ret = qe_devinit();
+ if (ret != OK)
+ {
+ message("qe_main: qe_devinit failed: %d\n", ret);
+ exitval = EXIT_FAILURE;
+ goto errout;
+ }
+
+ /* Set the default values */
+
+ qe_devpath(CONFIG_EXAMPLES_QENCODER_DEVPATH);
+ g_qeexample.initialized = true;
+ }
+
+ /* Parse command line arguments */
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ parse_args(argc, argv);
+#endif
+
+ /* Open the encoder device for reading */
+
+ message("qe_main: Hardware initialized. Opening the encoder device: %s\n",
+ g_qeexample.devpath);
+
+ fd = open(g_qeexample.devpath, O_RDONLY);
+ if (fd < 0)
+ {
+ message("qe_main: open %s failed: %d\n", g_qeexample.devpath, errno);
+ exitval = EXIT_FAILURE;
+ goto errout_with_dev;
+ }
+
+ /* Reset the count if so requested */
+
+ if (g_qeexample.reset)
+ {
+ message("qe_main: Resetting the count...\n");
+ ret = ioctl(fd, QEIOC_RESET, 0);
+ if (ret < 0)
+ {
+ message("qe_main: ioctl(QEIOC_RESET) failed: %d\n", errno);
+ exitval = EXIT_FAILURE;
+ goto errout_with_dev;
+ }
+ }
+
+ /* Now loop the appropriate number of times, displaying the collected
+ * encoder samples.
+ */
+
+#if defined(CONFIG_NSH_BUILTIN_APPS)
+ message("qe_main: Number of samples: %d\n", g_qeexample.nloops);
+ for (nloops = 0; nloops < g_qeexample.nloops; nloops++)
+#elif defined(CONFIG_EXAMPLES_QENCODER_NSAMPLES)
+ message("qe_main: Number of samples: %d\n", CONFIG_EXAMPLES_QENCODER_NSAMPLES);
+ for (nloops = 0; nloops < CONFIG_EXAMPLES_QENCODER_NSAMPLES; nloops++)
+#else
+ for (;;)
+#endif
+ {
+ /* Flush any output before the loop entered or from the previous pass
+ * through the loop.
+ */
+
+ msgflush();
+
+ /* Get the positions data using the ioctl */
+
+ ret = ioctl(fd, QEIOC_POSITION, (unsigned long)((uintptr_t)&position));
+ if (ret < 0)
+ {
+ message("qe_main: ioctl(QEIOC_POSITION) failed: %d\n", errno);
+ exitval = EXIT_FAILURE;
+ goto errout_with_dev;
+ }
+
+ /* Print the sample data on successful return */
+
+ else
+ {
+ message("qe_main: %3d. %d\n", nloops+1, position);
+ }
+
+ /* Delay a little bit */
+
+#if defined(CONFIG_NSH_BUILTIN_APPS)
+ usleep(g_qeexample.delay * 1000);
+#else
+ usleep(CONFIG_EXAMPLES_QENCODER_DELAY * 1000);
+#endif
+ }
+
+errout_with_dev:
+ close(fd);
+
+errout:
+ message("Terminating!\n");
+ msgflush();
+ return exitval;
+}
diff --git a/apps/examples/rgmp/Kconfig b/apps/examples/rgmp/Kconfig
new file mode 100644
index 000000000..f3accba9c
--- /dev/null
+++ b/apps/examples/rgmp/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_RGMP
+ bool "RGMP example"
+ default n
+ ---help---
+ Enable the RGMP example
+
+if EXAMPLES_RGMP
+endif
diff --git a/apps/examples/rgmp/Makefile b/apps/examples/rgmp/Makefile
new file mode 100644
index 000000000..3590bb0f0
--- /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 <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
+
+# The smallest thing you can build -- the NULL example.
+
+ASRCS =
+CSRCS = rgmp_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/rgmp_main.c b/apps/examples/rgmp/rgmp_main.c
new file mode 100644
index 000000000..e026852b8
--- /dev/null
+++ b/apps/examples/rgmp/rgmp_main.c
@@ -0,0 +1,66 @@
+/****************************************************************************
+ * examples/rgmp/rgmp_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 <stdio.h>
+#include <string.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * rgmp_main
+ ****************************************************************************/
+
+int rgmp_main(int argc, char *argv[])
+{
+ // TODO: add your code here
+
+ return 0;
+}
+
diff --git a/apps/examples/romfs/Kconfig b/apps/examples/romfs/Kconfig
new file mode 100644
index 000000000..5a8c824a3
--- /dev/null
+++ b/apps/examples/romfs/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_ROMFS
+ bool "ROMFS example"
+ default n
+ ---help---
+ Enable the ROMFS example
+
+if EXAMPLES_ROMFS
+endif
diff --git a/apps/examples/romfs/Makefile b/apps/examples/romfs/Makefile
new file mode 100644
index 000000000..ba930b77d
--- /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 <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
+
+# 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..3437cb8ac
--- /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 <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.
+ *
+ ****************************************************************************/
+
+/* 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: romfs_main
+ ****************************************************************************/
+
+int romfs_main(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
new file mode 100644
index 000000000..cd0e9c518
--- /dev/null
+++ b/apps/examples/romfs/testdir.tar.gz
Binary files differ
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/Kconfig b/apps/examples/sendmail/Kconfig
new file mode 100644
index 000000000..875820b16
--- /dev/null
+++ b/apps/examples/sendmail/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_SENDMAIL
+ bool "Sendmail example"
+ default n
+ ---help---
+ Enable the sendmail example
+
+if EXAMPLES_SENDMAIL
+endif
diff --git a/apps/examples/sendmail/Makefile b/apps/examples/sendmail/Makefile
new file mode 100644
index 000000000..6ee29d935
--- /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 <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
+
+# 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..bef7eebbf
--- /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 <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.
+#
+############################################################################
+
+# 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..a175d2e9a
--- /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 <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 <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 100644
index 000000000..e9860c22d
--- /dev/null
+++ b/apps/examples/sendmail/hostdefs.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+ * examples/wget/hostdefs.h
+ *
+ * Copyright (C) 2009 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.
+ *
+ *****************************************************************************/
+
+#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..8440c7813
--- /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 <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 <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
+ ****************************************************************************/
+
+/****************************************************************************
+ * sendmail_main
+ ****************************************************************************/
+
+int sendmail_main(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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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/Kconfig b/apps/examples/serloop/Kconfig
new file mode 100644
index 000000000..e52d35b3f
--- /dev/null
+++ b/apps/examples/serloop/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_SERLOOP
+ bool "Serial loopback example"
+ default n
+ ---help---
+ Enable the serial loopback example
+
+if EXAMPLES_SERLOOP
+endif
diff --git a/apps/examples/serloop/Makefile b/apps/examples/serloop/Makefile
new file mode 100644
index 000000000..e1c415cdd
--- /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 <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
+
+# Mindlessly simple console loopack test
+
+ASRCS =
+CSRCS = serloop_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/serloop_main.c b/apps/examples/serloop/serloop_main.c
new file mode 100644
index 000000000..af171fef3
--- /dev/null
+++ b/apps/examples/serloop/serloop_main.c
@@ -0,0 +1,100 @@
+/****************************************************************************
+ * examples/serloop/serloop_main.c
+ *
+ * Copyright (C) 2008-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 <unistd.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * serloop_main
+ ****************************************************************************/
+
+int serloop_main(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/telnetd/Kconfig b/apps/examples/telnetd/Kconfig
new file mode 100644
index 000000000..11f94a86f
--- /dev/null
+++ b/apps/examples/telnetd/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_TELNETD
+ bool "Telnet daemon example"
+ default n
+ ---help---
+ Enable the Telnet daemon example
+
+if EXAMPLES_TELNETD
+endif
diff --git a/apps/examples/telnetd/Makefile b/apps/examples/telnetd/Makefile
new file mode 100644
index 000000000..fe892670e
--- /dev/null
+++ b/apps/examples/telnetd/Makefile
@@ -0,0 +1,105 @@
+############################################################################
+# apps/examples/telnetd/Makefile
+#
+# Copyright (C) 2012 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
+
+# Hello, World! Example
+
+ASRCS =
+CSRCS = shell.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 = telnetd
+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/telnetd/README.txt b/apps/examples/telnetd/README.txt
new file mode 100644
index 000000000..ebc9684ca
--- /dev/null
+++ b/apps/examples/telnetd/README.txt
@@ -0,0 +1,8 @@
+README.txt
+^^^^^^^^^^
+
+This directory 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/examples/telnetd/shell.c b/apps/examples/telnetd/shell.c
new file mode 100644
index 000000000..3033698c5
--- /dev/null
+++ b/apps/examples/telnetd/shell.c
@@ -0,0 +1,255 @@
+/****************************************************************************
+ * examples/telnetd/shell.c
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/if.h>
+
+#include <apps/netutils/telnetd.h>
+#include <apps/netutils/uiplib.h>
+
+#include "shell.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct ptentry_s
+{
+ FAR const char *commandstr;
+ void (*pfunc)(int argc, char **argv);
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void shell_help(int argc, char **argv);
+static void shell_quit(int argc, char **argv);
+static void shell_unknown(int argc, char **argv);
+static void shell_parse(FAR char *line, int len);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct ptentry_s g_parsetab[] =
+{
+ {"help", shell_help},
+ {"exit", shell_quit},
+ {"?", shell_help},
+ {NULL, shell_unknown}
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: shell_help
+ ****************************************************************************/
+
+static void shell_help(int argc, char **argv)
+{
+ printf("Available commands:\n");
+ printf(" help, ? - show help\n");
+ printf(" exit - exit shell\n");
+}
+
+/****************************************************************************
+ * Name: shell_help
+ ****************************************************************************/
+
+static void shell_unknown(int argc, char **argv)
+{
+ if (argv[0])
+ {
+ printf("Unknown command: %s\n", argv[0]);
+ }
+}
+
+/****************************************************************************
+ * Name: shell_quit
+ ****************************************************************************/
+
+static void shell_quit(int argc, char **argv)
+{
+ printf("Bye!\n");
+ exit(0);
+}
+
+/****************************************************************************
+ * Name: shell_parse
+ ****************************************************************************/
+
+static void shell_parse(FAR char *line, int len)
+{
+ struct ptentry_s *entry;
+ FAR char *cmd;
+ FAR char *saveptr;
+
+ /* Get the command from the beginning the line */
+
+ cmd = strtok_r(line, " \t\n\r\f\v", &saveptr);
+ if (cmd)
+ {
+ /* Now find the matching command in the command table */
+
+ for (entry = g_parsetab; entry->commandstr != NULL; entry++)
+ {
+ if (strncmp(entry->commandstr, cmd, strlen(entry->commandstr)) == 0)
+ {
+ break;
+ }
+ }
+
+ entry->pfunc(1, &cmd);
+ }
+}
+
+/****************************************************************************
+ * Name: shell_session
+ ****************************************************************************/
+
+int shell_session(int argc, char *argv[])
+{
+ char line[128];
+
+ printf("uIP command shell -- NuttX style\n");
+ printf("Type '?' and return for help\n");
+
+ for(;;)
+ {
+ printf(SHELL_PROMPT);
+ fflush(stdout);
+
+ if (fgets(line, 128, stdin) == NULL)
+ {
+ break;
+ }
+
+ shell_parse(line, 128);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: shell_netinit
+ ****************************************************************************/
+
+static void shell_netinit(void)
+{
+ struct in_addr addr;
+#ifdef CONFIG_EXAMPLE_TELNETD_NOMAC
+ uint8_t mac[IFHWADDRLEN];
+#endif
+
+/* Many embedded network interfaces must have a software assigned MAC */
+
+#ifdef CONFIG_EXAMPLE_TELNETD_NOMAC
+ mac[0] = 0x00;
+ mac[1] = 0xe0;
+ mac[2] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ uip_setmacaddr("eth0", mac);
+#endif
+
+ /* Set up our host address */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLE_TELNETD_IPADDR);
+ uip_sethostaddr("eth0", &addr);
+
+ /* Set up the default router address */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLE_TELNETD_DRIPADDR);
+ uip_setdraddr("eth0", &addr);
+
+ /* Setup the subnet mask */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLE_TELNETD_NETMASK);
+ uip_setnetmask("eth0", &addr);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int shell_main(int argc, char *argv[])
+{
+ struct telnetd_config_s config;
+ int ret;
+
+ /* Configure the network */
+
+ printf("shell_main: Initializing the network\n");
+ shell_netinit();
+
+ /* Configure the telnet daemon */
+
+ config.d_port = HTONS(23);
+ config.d_priority = CONFIG_EXAMPLES_TELNETD_DAEMONPRIO;
+ config.d_stacksize = CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE;
+ config.t_priority = CONFIG_EXAMPLES_TELNETD_CLIENTPRIO;
+ config.t_stacksize = CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE;
+ config.t_entry = shell_session;
+
+ /* Start the telnet daemon */
+
+ printf("shell_main: Starting the Telnet daemon\n");
+ ret = telnetd_start(&config);
+ if (ret < 0)
+ {
+ printf("Failed to tart the Telnet daemon\n");
+ }
+
+ printf("shell_main: Exiting\n");
+ return 0;
+}
diff --git a/apps/examples/telnetd/shell.h b/apps/examples/telnetd/shell.h
new file mode 100644
index 000000000..a5cec32b3
--- /dev/null
+++ b/apps/examples/telnetd/shell.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+ * apps/examples/telnetd/shell.h
+ * Interface for the Contiki shell.
+ *
+ * Copyright (C) 2012 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. 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_EXAMPLES_TELNETD_SHELL_H
+#define __APPS_EXAMPLES_TELNETD_SHELL_H
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* CONFIG_EXAMPLES_TELNETD_DAEMONPRIO - Priority of the Telnet daemon.
+ * Default: SCHED_PRIORITY_DEFAULT
+ * CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the
+ * Telnet daemon. Default: 2048
+ * CONFIG_EXAMPLES_TELNETD_CLIENTPRIO- Priority of the Telnet client.
+ * Default: SCHED_PRIORITY_DEFAULT
+ * CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the
+ * Telnet client. Default: 2048
+ * CONFIG_EXAMPLE_TELNETD_NOMAC - If the hardware has no MAC address of its
+ * own, define this =y to provide a bogus address for testing.
+ * CONFIG_EXAMPLE_TELNETD_IPADDR - The target IP address. Default 10.0.0.2
+ * CONFIG_EXAMPLE_TELNETD_DRIPADDR - The default router address. Default
+ * 10.0.0.1
+ * CONFIG_EXAMPLE_TELNETD_NETMASK - The network mask. Default: 255.255.255.0
+ */
+
+#ifndef CONFIG_EXAMPLES_TELNETD_DAEMONPRIO
+# define CONFIG_EXAMPLES_TELNETD_DAEMONPRIO SCHED_PRIORITY_DEFAULT
+#endif
+
+#ifndef CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE
+# define CONFIG_EXAMPLES_TELNETD_DAEMONSTACKSIZE 2048
+#endif
+
+#ifndef CONFIG_EXAMPLES_TELNETD_CLIENTPRIO
+# define CONFIG_EXAMPLES_TELNETD_CLIENTPRIO SCHED_PRIORITY_DEFAULT
+#endif
+
+#ifndef CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE
+# define CONFIG_EXAMPLES_TELNETD_CLIENTSTACKSIZE 2048
+#endif
+
+#ifndef CONFIG_EXAMPLE_TELNETD_IPADDR
+# define CONFIG_EXAMPLE_TELNETD_IPADDR 0x0a000002
+#endif
+#ifndef CONFIG_EXAMPLE_TELNETD_DRIPADDR
+# define CONFIG_EXAMPLE_TELNETD_DRIPADDR 0x0a000002
+#endif
+#ifndef CONFIG_EXAMPLE_TELNETD_NETMASK
+# define CONFIG_EXAMPLE_TELNETD_NETMASK 0xffffff00
+#endif
+
+/* Other definitions ********************************************************/
+
+#define SHELL_PROMPT "uIP 1.0> "
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#endif /* __APPS_EXAMPLES_TELNETD_SHELL_H */
diff --git a/apps/examples/thttpd/Kconfig b/apps/examples/thttpd/Kconfig
new file mode 100644
index 000000000..d5802f531
--- /dev/null
+++ b/apps/examples/thttpd/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_THTTPD
+ bool "THTTPD web server example"
+ default n
+ ---help---
+ Enable the THTTPD web server example
+
+if EXAMPLES_THTTPD
+endif
diff --git a/apps/examples/thttpd/Makefile b/apps/examples/thttpd/Makefile
new file mode 100644
index 000000000..897f15b33
--- /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 <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
+
+# THTTPD Web Server Example
+
+ASRCS =
+CSRCS = thttpd_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..1f5ce4246
--- /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 <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.
+#
+############################################################################
+
+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..76d4e67c8
--- /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 <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
+-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..386759fc2
--- /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 <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 <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..9769c9207
--- /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 <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
+-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 100644
index 000000000..9aec0c81c
--- /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 <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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <netinet/ether.h>
+#include <nuttx/net/uip/uipopt.h>
+#include <nuttx/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 100644
index 000000000..b76c3f22a
--- /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 <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
+-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 100644
index 000000000..e2eedf781
--- /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 <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 <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/thttpd_main.c b/apps/examples/thttpd/thttpd_main.c
new file mode 100644
index 000000000..f4d5d58db
--- /dev/null
+++ b/apps/examples/thttpd/thttpd_main.c
@@ -0,0 +1,267 @@
+/****************************************************************************
+ * examples/thttpd/thttpd_main.c
+ *
+ * Copyright (C) 2009-2012 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 <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 <nuttx/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/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
+ ****************************************************************************/
+
+/****************************************************************************
+ * thttp_main
+ ****************************************************************************/
+
+int thttp_main(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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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/Kconfig b/apps/examples/tiff/Kconfig
new file mode 100644
index 000000000..f3c5c4ebe
--- /dev/null
+++ b/apps/examples/tiff/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_TIFF
+ bool "TIFF file generation example"
+ default n
+ ---help---
+ Enable the TIFF file generation example
+
+if EXAMPLES_TIFF
+endif
diff --git a/apps/examples/tiff/Makefile b/apps/examples/tiff/Makefile
new file mode 100644
index 000000000..22611a400
--- /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 <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
+
+# 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..1bf931a43
--- /dev/null
+++ b/apps/examples/tiff/tiff_main.c
@@ -0,0 +1,168 @@
+/****************************************************************************
+ * apps/graphics/tiff/tiff_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 <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
+ *
+ * Description:
+ * TIFF unit test.
+ *
+ ****************************************************************************/
+
+int tiff_main(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/Kconfig b/apps/examples/touchscreen/Kconfig
new file mode 100644
index 000000000..e8d8728d8
--- /dev/null
+++ b/apps/examples/touchscreen/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_TOUCHSCREEN
+ bool "Touchscreen example"
+ default n
+ ---help---
+ Enable the touchscreen example
+
+if EXAMPLES_TOUCHSCREEN
+endif
diff --git a/apps/examples/touchscreen/Makefile b/apps/examples/touchscreen/Makefile
new file mode 100644
index 000000000..bd32f9f60
--- /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 <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
+
+# 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..654b1d874
--- /dev/null
+++ b/apps/examples/touchscreen/tc.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+ * examples/touchscreen/tc.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#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
+ ****************************************************************************/
+
+#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..79b6b65a3
--- /dev/null
+++ b/apps/examples/touchscreen/tc_main.c
@@ -0,0 +1,208 @@
+/****************************************************************************
+ * examples/touchscreen/tc_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/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: tc_main
+ ****************************************************************************/
+
+int tc_main(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("tc_main: nsamples: %d\n", nsamples);
+#elif defined(CONFIG_EXAMPLES_TOUCHSCREEN_NSAMPLES)
+ message("tc_main: nsamples: %d\n", CONFIG_EXAMPLES_TOUCHSCREEN_NSAMPLES);
+#endif
+
+ /* Initialization of the touchscreen hardware is performed by logic
+ * external to this test.
+ */
+
+ message("tc_main: Initializing external touchscreen device\n");
+ ret = arch_tcinitialize(CONFIG_EXAMPLES_TOUCHSCREEN_MINOR);
+ if (ret != OK)
+ {
+ message("tc_main: arch_tcinitialize failed: %d\n", ret);
+ errval = 1;
+ goto errout;
+ }
+
+ /* Open the touchscreen device for reading */
+
+ message("tc_main: Opening %s\n", CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH);
+ fd = open(CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH, O_RDONLY);
+ if (fd < 0)
+ {
+ message("tc_main: 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 */
+
+ ivdbg("Reading...\n");
+ 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("tc_main: read %s failed: %d\n",
+ CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH, errval);
+ errval = 3;
+ goto errout_with_dev;
+ }
+
+ message("tc_main: Interrupted read...\n");
+ }
+ else if (nbytes != sizeof(struct touch_sample_s))
+ {
+ message("tc_main: 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/Kconfig b/apps/examples/udp/Kconfig
new file mode 100644
index 000000000..24df27375
--- /dev/null
+++ b/apps/examples/udp/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_UDP
+ bool "UDP example"
+ default n
+ ---help---
+ Enable the UDP example
+
+if EXAMPLES_UDP
+endif
diff --git a/apps/examples/udp/Makefile b/apps/examples/udp/Makefile
new file mode 100644
index 000000000..337d323e8
--- /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 <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
+
+# 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..9d2aa73d9
--- /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 <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 "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..e43ff2a0b
--- /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 <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 <stdio.h>
+#include <debug.h>
+
+#include <nuttx/net/uip/uip.h>
+#include <apps/netutils/uiplib.h>
+
+#include "udp-internal.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * udp_main
+ ****************************************************************************/
+
+int udp_main(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..fb98ab342
--- /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 <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 <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..04a685d17
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..1f4774deb
--- /dev/null
+++ b/apps/examples/udp/udp-server.c
@@ -0,0 +1,173 @@
+/****************************************************************************
+ * examples/udp/udp-server.c
+ *
+ * Copyright (C) 2007, 2009, 2012 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 <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/Kconfig b/apps/examples/uip/Kconfig
new file mode 100644
index 000000000..db65995c8
--- /dev/null
+++ b/apps/examples/uip/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_UIP
+ bool "uIP web server example"
+ default n
+ ---help---
+ Enable the uIP web server example
+
+if EXAMPLES_UIP
+endif
diff --git a/apps/examples/uip/Makefile b/apps/examples/uip/Makefile
new file mode 100644
index 000000000..218f6f3c6
--- /dev/null
+++ b/apps/examples/uip/Makefile
@@ -0,0 +1,98 @@
+############################################################################
+# apps/examples/uip/Makefile
+#
+# Copyright (C) 2007-2008, 2010-2012 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
+
+# uIP very tiny web server example
+
+ASRCS =
+CSRCS = uip_main.c cgi.c httpd_fsdata.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
+
+httpd_fsdata.c: httpd-fs/*
+ $(TOPDIR)/tools/mkfsdata.pl
+
+context:
+
+.depend: Makefile $(SRCS)
+ @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
+ @touch $@
+
+epend: .depend
+
+clean:
+ @rm -f *.o *~ .*.swp .built
+ @rm -f httpd_fsdata.c
+ $(call CLEAN)
+
+distclean: clean
+ @rm -f Make.dep .depend
+
+-include Make.dep
+
diff --git a/apps/examples/uip/cgi.c b/apps/examples/uip/cgi.c
new file mode 100644
index 000000000..8d081db92
--- /dev/null
+++ b/apps/examples/uip/cgi.c
@@ -0,0 +1,108 @@
+/****************************************************************************
+ * apps/examples/uip/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 <apps/netutils/httpd.h>
+
+#include "cgi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#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
+
+/****************************************************************************
+ * 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));
+ send(pstate->ht_sockfd, buffer, strlen(buffer), 0);
+}
+#endif
+
+/****************************************************************************
+ * Name: cgi_register
+ ****************************************************************************/
+
+void cgi_register()
+{
+#ifdef CONFIG_NETUTILS_HTTPDFILESTATS
+ httpd_cgi_register(&file);
+#endif
+
+#ifdef CONFIG_NETUTILS_HTTPDNETSTATS
+ httpd_cgi_register(&net);
+#endif
+}
diff --git a/apps/examples/uip/cgi.h b/apps/examples/uip/cgi.h
new file mode 100644
index 000000000..8ad0f93ce
--- /dev/null
+++ b/apps/examples/uip/cgi.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+ * apps/examples/uip/cgi.c
+ * 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__
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+void cgi_register(void);
+
+#endif /* __HTTPD_CGI_H__ */
diff --git a/apps/examples/uip/httpd-fs/404.html b/apps/examples/uip/httpd-fs/404.html
new file mode 100644
index 000000000..a17711d02
--- /dev/null
+++ b/apps/examples/uip/httpd-fs/404.html
@@ -0,0 +1,8 @@
+<html>
+ <body bgcolor="white">
+ <center>
+ <h1>404 - file not found</h1>
+ <h3>Go <a href="/">here</a> instead.</h3>
+ </center>
+ </body>
+</html> \ No newline at end of file
diff --git a/apps/examples/uip/httpd-fs/fade.png b/apps/examples/uip/httpd-fs/fade.png
new file mode 100644
index 000000000..a9e69f75d
--- /dev/null
+++ b/apps/examples/uip/httpd-fs/fade.png
Binary files differ
diff --git a/apps/examples/uip/httpd-fs/files.shtml b/apps/examples/uip/httpd-fs/files.shtml
new file mode 100644
index 000000000..8a90dbd6d
--- /dev/null
+++ b/apps/examples/uip/httpd-fs/files.shtml
@@ -0,0 +1,31 @@
+%!: /header.html
+<h1>File statistics</h1>
+<center>
+<table width="300">
+<tr><td><a href="/index.shtml">/index.shtml</a></td>
+<td>%! file-stats /index.shtml
+</td><td><img src="/fade.png" height=10 width=%! file-stats /index.shtml
+> </td></tr>
+<tr><td><a href="/files.shtml">/files.shtml</a></td>
+<td>%! file-stats /files.shtml
+</td><td><img src="/fade.png" height=10 width=%! file-stats /files.shtml
+> </td></tr>
+<tr><td><a href="/stats.shtml">/stats.shtml</a></td>
+<td>%! file-stats /stats.shtml
+</td><td><img src="/fade.png" height=10 width=%! file-stats /stats.shtml
+> </td></tr>
+<tr><td><a href="/style.css">/style.css</a></td>
+<td>%! file-stats /style.css
+</td><td><img src="/fade.png" height=10 width=%! file-stats /style.css
+> </td></tr>
+<tr><td><a href="/404.html">/404.html</a></td>
+<td>%! file-stats /404.html
+</td><td><img src="/fade.png" height=10 width=%! file-stats /404.html
+> </td></tr>
+<tr><td><a href="/fade.png">/fade.png</a></td>
+<td>%! file-stats /fade.png
+</td><td><img src="/fade.png" height=10 width=%! file-stats /fade.png
+> </td></tr>
+</table>
+</center>
+%!: /footer.html
diff --git a/apps/examples/uip/httpd-fs/footer.html b/apps/examples/uip/httpd-fs/footer.html
new file mode 100644
index 000000000..5b6e2d653
--- /dev/null
+++ b/apps/examples/uip/httpd-fs/footer.html
@@ -0,0 +1,3 @@
+ </div>
+ </body>
+</html>
diff --git a/apps/examples/uip/httpd-fs/header.html b/apps/examples/uip/httpd-fs/header.html
new file mode 100644
index 000000000..70df07fa6
--- /dev/null
+++ b/apps/examples/uip/httpd-fs/header.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>Welcome to the uIP web server!</title>
+ <link rel="stylesheet" type="text/css" href="style.css">
+ </head>
+ <body bgcolor="#fffeec" text="black">
+
+ <div class="menu">
+ <div class="menubox"><a href="/">Front page</a></div>
+ <div class="menubox"><a href="files.shtml">File statistics</a></div>
+ <div class="menubox"><a href="stats.shtml">Network statistics</a></div>
+ <br>
+ </div>
+
+ <div class="contentblock">
diff --git a/apps/examples/uip/httpd-fs/index.shtml b/apps/examples/uip/httpd-fs/index.shtml
new file mode 100644
index 000000000..7f19358ce
--- /dev/null
+++ b/apps/examples/uip/httpd-fs/index.shtml
@@ -0,0 +1,10 @@
+%!: /header.html
+ <p>
+ These web pages are served by a small web server running on top of
+ the <a href="http://www.sics.se/~adam/uip/">uIP embedded TCP/IP
+ stack</a>.
+ </p>
+ <p>
+ Click on the links above for web server statistics.
+ </p>
+%!: /footer.html
diff --git a/apps/examples/uip/httpd-fs/stats.shtml b/apps/examples/uip/httpd-fs/stats.shtml
new file mode 100644
index 000000000..c63ed4afd
--- /dev/null
+++ b/apps/examples/uip/httpd-fs/stats.shtml
@@ -0,0 +1,31 @@
+%!: /header.html
+<h1>Network statistics</h1>
+<center>
+<table width="300" border="0">
+<tr><td><pre>
+IP Packets received
+ Packets sent
+ Packets dropped
+IP errors IP version/header length
+ IP length, high byte
+ IP length, low byte
+ IP fragments
+ Header checksum
+ Wrong protocol
+ICMP Packets received
+ Packets sent
+ Packets dropped
+ Type errors
+TCP Packets received
+ Packets sent
+ Packets dropped
+ Checksum errors
+ Data packets without ACKs
+ Resets
+ Retransmissions
+ No connection avaliable
+ Connection attempts to closed ports
+</pre></td><td><pre>%! net-stats
+</pre></table>
+</center>
+%!: /footer.html
diff --git a/apps/examples/uip/httpd-fs/style.css b/apps/examples/uip/httpd-fs/style.css
new file mode 100644
index 000000000..ba6df7f15
--- /dev/null
+++ b/apps/examples/uip/httpd-fs/style.css
@@ -0,0 +1,92 @@
+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-weight:bold; */
+ 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/uip/httpd-fs/tcp.shtml b/apps/examples/uip/httpd-fs/tcp.shtml
new file mode 100644
index 000000000..4c4bffe97
--- /dev/null
+++ b/apps/examples/uip/httpd-fs/tcp.shtml
@@ -0,0 +1,5 @@
+%!: /header.html
+<h1>Current connections</h1><br><table width="100%">
+<tr><th>Local</th><th>Remote</th><th>State</th><th>Retransmissions</th><th>Timer</th><th>Flags</th></tr>
+%! tcp-connections
+%!: /footer.html \ No newline at end of file
diff --git a/apps/examples/uip/uip_main.c b/apps/examples/uip/uip_main.c
new file mode 100644
index 000000000..b552aed75
--- /dev/null
+++ b/apps/examples/uip/uip_main.c
@@ -0,0 +1,210 @@
+/****************************************************************************
+ * examples/uip/uip_main.c
+ *
+ * Copyright (C) 2007, 2009-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <nuttx/net/uip/uip.h>
+#include <nuttx/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>
+
+#include "cgi.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
+ ****************************************************************************/
+
+/****************************************************************************
+ * uip_main
+ ****************************************************************************/
+
+int uip_main(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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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();
+ cgi_register();
+ httpd_listen();
+#endif
+
+ while(1)
+ {
+ sleep(3);
+ printf("uip_main: Still running\n");
+#if CONFIG_NFILE_DESCRIPTORS > 0
+ fflush(stdout);
+#endif
+ }
+ return 0;
+}
diff --git a/apps/examples/usbserial/Kconfig b/apps/examples/usbserial/Kconfig
new file mode 100644
index 000000000..33a0243eb
--- /dev/null
+++ b/apps/examples/usbserial/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_USBSERIAL
+ bool "USB serial test example"
+ default n
+ ---help---
+ Enable the USB serial test example
+
+if EXAMPLES_USBSERIAL
+endif
diff --git a/apps/examples/usbserial/Makefile b/apps/examples/usbserial/Makefile
new file mode 100644
index 000000000..4b6bd8948
--- /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 <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
+
+# USB serial device example
+
+ASRCS =
+CSRCS = usbserial_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..628304cd4
--- /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 <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.
+#
+############################################################################
+
+# 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..366b62223
--- /dev/null
+++ b/apps/examples/usbserial/host.c
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * examples/usbserial/host.c
+ *
+ * Copyright (C) 2008 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 <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
+
+#ifdef CONFIG_CDCACM
+# define DEFAULT_TTYDEV "/dev/ttyACM0"
+#else
+# define DEFAULT_TTYDEV "/dev/ttyUSB0"
+#endif
+#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/usbserial_main.c b/apps/examples/usbserial/usbserial_main.c
new file mode 100644
index 000000000..016c8b292
--- /dev/null
+++ b/apps/examples/usbserial/usbserial_main.c
@@ -0,0 +1,467 @@
+/****************************************************************************
+ * examples/usbserial/usbserial_main.c
+ *
+ * Copyright (C) 2008, 2010-2012 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 <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_CDCACM
+# include <nuttx/usb/cdcacm.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
+
+#ifdef CONFIG_CDCACM
+# define USBSER_DEVNAME "/dev/ttyACM0"
+#else
+# define USBSER_DEVNAME "/dev/ttyUSB0"
+#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
+ ****************************************************************************/
+
+/****************************************************************************
+ * usbserial_main
+ ****************************************************************************/
+
+int usbserial_main(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("usbserial_main: Registering USB serial driver\n");
+#ifdef CONFIG_CDCACM
+ ret = cdcacm_initialize(0, NULL);
+#else
+ ret = usbdev_serialinitialize(0);
+#endif
+ if (ret < 0)
+ {
+ message("usbserial_main: ERROR: Failed to create the USB serial device: %d\n", -ret);
+ return 1;
+ }
+ message("usbserial_main: 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("usbserial_main: Opening USB serial driver\n");
+ outfd = open(USBSER_DEVNAME, O_WRONLY);
+ if (outfd < 0)
+ {
+ int errcode = errno;
+ message("usbserial_main: ERROR: Failed to open " USBSER_DEVNAME " for writing: %d\n", errcode);
+
+ /* ENOTCONN means that the USB device is not yet connected */
+
+ if (errcode == ENOTCONN)
+ {
+ message("usbserial_main: Not connected. Wait and try again.\n");
+ sleep(5);
+ }
+ else
+ {
+ /* Give up on other errors */
+
+ message("usbserial_main: 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(USBSER_DEVNAME, O_RDONLY|O_NONBLOCK);
+ if (infd < 0)
+ {
+ message("usbserial_main: ERROR: Failed to open " USBSER_DEVNAME " for reading: %d\n", errno);
+ close(outfd);
+ return 3;
+ }
+#else
+ do
+ {
+ infd = open(USBSER_DEVNAME, O_RDONLY|O_NONBLOCK);
+ if (infd < 0)
+ {
+ int errcode = errno;
+ message("usbserial_main: ERROR: Failed to open " USBSER_DEVNAME " for reading: %d\n", errno);
+
+ /* ENOTCONN means that the USB device is not yet connected */
+
+ if (errcode == ENOTCONN)
+ {
+ message("usbserial_main: Not connected. Wait and try again.\n");
+ sleep(5);
+ }
+ else
+ {
+ /* Give up on other errors */
+
+ message("usbserial_main: Aborting\n");
+ return 3;
+ }
+ }
+
+ /* If USB tracing is enabled, then dump all collected trace data to stdout */
+
+ dumptrace();
+ }
+ while (infd < 0);
+#endif
+#endif
+
+ message("usbserial_main: 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("usbserial_main: Saying hello\n");
+ nbytes = write(outfd, g_shortmsg, sizeof(g_shortmsg));
+ count++;
+ }
+ else
+ {
+ message("usbserial_main: Reciting QEI's speech of 1588\n");
+ nbytes = write(outfd, g_longmsg, sizeof(g_longmsg));
+ count = 0;
+ }
+#elif !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYSMALL)
+ message("usbserial_main: Reciting QEI's speech of 1588\n");
+ nbytes = write(outfd, g_longmsg, sizeof(g_longmsg));
+#else /* !defined(CONFIG_EXAMPLES_USBSERIAL_ONLYBIG) */
+ message("usbserial_main: Saying hello\n");
+ nbytes = write(outfd, g_shortmsg, sizeof(g_shortmsg));
+#endif
+
+ /* Test if the write was successful */
+
+ if (nbytes < 0)
+ {
+ message("usbserial_main: ERROR: write failed: %d\n", errno);
+#ifndef CONFIG_EXAMPLES_USBSERIAL_INONLY
+ close(infd);
+#endif
+ close(outfd);
+ return 4;
+ }
+ message("usbserial_main: %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("usbserial_main: 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("usbserial_main: ERROR: read failed: %d\n", errno);
+ close(infd);
+#ifndef CONFIG_EXAMPLES_USBSERIAL_OUTONLY
+ close(outfd);
+#endif
+ return 6;
+ }
+ }
+ else
+ {
+ message("usbserial_main: Received %d bytes:\n", nbytes);
+ if (nbytes > 0)
+ {
+ for (j = 0; j < nbytes; j += 16)
+ {
+ message("usbserial_main: %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("usbserial_main: 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/Kconfig b/apps/examples/usbstorage/Kconfig
new file mode 100644
index 000000000..96af82b21
--- /dev/null
+++ b/apps/examples/usbstorage/Kconfig
@@ -0,0 +1,136 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_USBMSC
+ bool "USB mass storage class example"
+ default n
+ ---help---
+ Enable the USB mass storage class example
+
+config EXAMPLES_USBMSC_BUILTIN
+ bool "NSH built-in command"
+ default y
+ depends on EXAMPLES_USBMSC && NSH_BUILTIN_APPS
+ ---help---
+ This example can be built as two NSH "built-in" commands if this
+ option is selected: 'msconn' will connect the USB mass storage
+ device; 'msdis' will disconnect the USB storage device.
+
+config EXAMPLES_USBMSC_NLUNS
+ int "Number of LUNs"
+ default 1
+ depends on EXAMPLES_USBMSC
+ ---help---
+ 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_USBMSC_DEVMINOR1
+ int "LUN1 Minor Device Number"
+ default 0
+ depends on EXAMPLES_USBMSC
+ ---help---
+ 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_USBMSC_DEVPATH1
+ string "LUN1 Device Path"
+ default "/dev/mmcsd0"
+ depends on EXAMPLES_USBMSC
+ ---help---
+ The full path to the registered block driver. Default is
+ "/dev/mmcsd0"
+
+config EXAMPLES_USBMSC_DEVMINOR2
+ int "LUN2 Minor Device Number"
+ default 1
+ depends on EXAMPLES_USBMSC
+ ---help---
+ The minor device number of the block driver for the second LUN. For
+ example, N in /dev/mmcsdN. Used for registering the block driver.
+ Ignored if EXAMPLES_USBMSC_NLUNS < 2. Default is one.
+
+config EXAMPLES_USBMSC_DEVPATH2
+ string "LUN2 Device Path"
+ default "/dev/mmcsd1"
+ depends on EXAMPLES_USBMSC
+ ---help---
+ The full path to the registered block driver. Ignored if
+ EXAMPLES_USBMSC_NLUNS < 2. Default is "/dev/mmcsd1"
+
+config EXAMPLES_USBMSC_DEVMINOR3
+ int "LUN3 Minor Device Number"
+ default 2
+ depends on EXAMPLES_USBMSC
+ ---help---
+ The minor device number of the block driver for the third LUN. For
+ example, N in /dev/mmcsdN. Used for registering the block driver.
+ Ignored if EXAMPLES_USBMSC_NLUNS < 2. Default is two.
+
+config EXAMPLES_USBMSC_DEVPATH3
+ string "LUN3 Device Path"
+ default "/dev/mmcsd2"
+ depends on EXAMPLES_USBMSC
+ ---help---
+ The full path to the registered block driver. Ignored if
+ EXAMPLES_USBMSC_NLUNS < 2. Default is "/dev/mmcsd2"
+
+config EXAMPLES_USBMSC_DEBUGMM
+ bool "USB MSC MM Debug"
+ default n
+ depends on EXAMPLES_USBMSC
+ ---help---
+ Enables some debug tests to check for memory usage and memory leaks.
+
+config EXAMPLES_USBMSC_TRACEINIT
+ bool "USB Trace Initialization"
+ default n
+ depends on EXAMPLES_USBMSC
+ ---help---
+ If 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 this configuration value:
+ This setting will show USB initialization events
+
+config EXAMPLES_USBMSC_TRACECLASS
+ bool "USB Trace Class"
+ default n
+ depends on EXAMPLES_USBMSC
+ ---help---
+ If 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 this configuration value:
+ This setting will show USB class driver events
+
+config EXAMPLES_USBMSC_TRACETRANSFERS
+ bool "USB Trace Transfers"
+ default n
+ depends on EXAMPLES_USBMSC
+ ---help---
+ If 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 this configuration value:
+ This setting will show USB data transfer events
+
+config EXAMPLES_USBMSC_TRACECONTROLLER
+ bool "USB Trace Device Controller Events"
+ default n
+ depends on EXAMPLES_USBMSC
+ ---help---
+ If 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 this configuration value:
+ This setting will show USB device controller events
+
+config EXAMPLES_USBMSC_TRACEINTERRUPTS
+ bool "USB Trace Device Controller Interrupt Events"
+ default n
+ depends on EXAMPLES_USBMSC
+ ---help---
+ If 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 this configuration value:
+ This setting will show USB device controller interrupt-related events.
diff --git a/apps/examples/usbstorage/Makefile b/apps/examples/usbstorage/Makefile
new file mode 100644
index 000000000..d68a759e8
--- /dev/null
+++ b/apps/examples/usbstorage/Makefile
@@ -0,0 +1,111 @@
+############################################################################
+# apps/examples/usbstorage/Makefile
+#
+# Copyright (C) 2008, 2010-2012 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
+
+# USB device mass storage example
+
+ASRCS =
+CSRCS = usbmsc_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_USBMSC_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/usbmsc.h b/apps/examples/usbstorage/usbmsc.h
new file mode 100644
index 000000000..9d48c4521
--- /dev/null
+++ b/apps/examples/usbstorage/usbmsc.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+ * examples/usbstorage/usbmsc.h
+ *
+ * Copyright (C) 2008-2009, 2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __EXAMPLES_USBSTORAGE_USBMSC_H
+#define __EXAMPLES_USBSTORAGE_USBMSC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdlib.h>
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_EXAMPLES_USBMSC_NLUNS
+# define CONFIG_EXAMPLES_USBMSC_NLUNS 1
+#endif
+
+#ifndef CONFIG_EXAMPLES_USBMSC_DEVMINOR1
+# define CONFIG_EXAMPLES_USBMSC_DEVMINOR1 0
+#endif
+
+#ifndef CONFIG_EXAMPLES_USBMSC_DEVPATH1
+# define CONFIG_EXAMPLES_USBMSC_DEVPATH1 "/dev/mmcsd0"
+#endif
+
+#if CONFIG_EXAMPLES_USBMSC_NLUNS > 1
+# ifndef CONFIG_EXAMPLES_USBMSC_DEVMINOR2
+# error "CONFIG_EXAMPLES_USBMSC_DEVMINOR2 for LUN=2"
+# endif
+# ifndef CONFIG_EXAMPLES_USBMSC_DEVPATH2
+# error "CONFIG_EXAMPLES_USBMSC_DEVPATH2 for LUN=2"
+# endif
+# if CONFIG_EXAMPLES_USBMSC_NLUNS > 2
+# ifndef CONFIG_EXAMPLES_USBMSC_DEVMINOR3
+# error "CONFIG_EXAMPLES_USBMSC_DEVMINOR2 for LUN=3"
+# endif
+# ifndef CONFIG_EXAMPLES_USBMSC_DEVPATH2
+# error "CONFIG_EXAMPLES_USBMSC_DEVPATH2 for LUN=3"
+# endif
+# if CONFIG_EXAMPLES_USBMSC_NLUNS > 3
+# error "CONFIG_EXAMPLES_USBMSC_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_USBMSC_BUILTIN) || defined(CONFIG_EXAMPLES_USBMSC_DEBUGMM)
+struct usbmsc_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_USBMSC_BUILTIN. In this case, the value
+ * of the driver handle must be remembered between the 'msconn' and 'msdis'
+ * commands.
+ */
+
+#ifdef CONFIG_EXAMPLES_USBMSC_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_USBMSC_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_USBMSC_BUILTIN) || defined(CONFIG_EXAMPLES_USBMSC_DEBUGMM)
+extern struct usbmsc_state_s g_usbmsc;
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbmsc_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 usbmsc_archinitialize(void);
+
+#endif /* __EXAMPLES_USBSTORAGE_USBMSC_H */
diff --git a/apps/examples/usbstorage/usbmsc_main.c b/apps/examples/usbstorage/usbmsc_main.c
new file mode 100644
index 000000000..ac7b82d01
--- /dev/null
+++ b/apps/examples/usbstorage/usbmsc_main.c
@@ -0,0 +1,588 @@
+/****************************************************************************
+ * examples/usbstorage/usbmsc_main.c
+ *
+ * Copyright (C) 2008-2012 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 "usbmsc.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_EXAMPLES_USBMSC_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_USBMSC_TRACECLASS
+# define TRACE_CLASS_BITS (TRACE_CLASS_BIT|TRACE_CLASSAPI_BIT|TRACE_CLASSSTATE_BIT)
+#else
+# define TRACE_CLASS_BITS (0)
+#endif
+
+#ifdef CONFIG_EXAMPLES_USBMSC_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_USBMSC_TRACECONTROLLER
+# define TRACE_CONTROLLER_BITS (TRACE_EP_BIT|TRACE_DEV_BIT)
+#else
+# define TRACE_CONTROLLER_BITS (0)
+#endif
+
+#ifdef CONFIG_EXAMPLES_USBMSC_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_USBMSC_BUILTIN) || defined(CONFIG_EXAMPLES_USBMSC_DEBUGMM)
+struct usbmsc_state_s g_usbmsc;
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: show_memory_usage
+ ****************************************************************************/
+
+#ifdef CONFIG_EXAMPLES_USBMSC_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_USBMSC_DEBUGMM
+static void check_test_memory_usage(FAR const char *msg)
+{
+ /* Get the current memory usage */
+
+#ifdef CONFIG_CAN_PASS_STRUCTS
+ g_usbmsc.mmcurrent = mallinfo();
+#else
+ (void)mallinfo(&g_usbmsc.mmcurrent);
+#endif
+
+ /* Show the change from the previous time */
+
+ message("\%s:\n", msg);
+ show_memory_usage(&g_usbmsc.mmprevious, &g_usbmsc.mmcurrent);
+
+ /* Set up for the next test */
+
+#ifdef CONFIG_CAN_PASS_STRUCTS
+ g_usbmsc.mmprevious = g_usbmsc.mmcurrent;
+#else
+ memcpy(&g_usbmsc.mmprevious, &g_usbmsc.mmcurrent, sizeof(struct mallinfo));
+#endif
+}
+#else
+# define check_test_memory_usage(msg)
+#endif
+
+/****************************************************************************
+ * Name: check_test_memory_usage
+ ****************************************************************************/
+
+#ifdef CONFIG_EXAMPLES_USBMSC_DEBUGMM
+static void final_memory_usage(FAR const char *msg)
+{
+ /* Get the current memory usage */
+
+#ifdef CONFIG_CAN_PASS_STRUCTS
+ g_usbmsc.mmcurrent = mallinfo();
+#else
+ (void)mallinfo(&g_usbmsc.mmcurrent);
+#endif
+
+ /* Show the change from the previous time */
+
+ message("\n%s:\n", msg);
+ show_memory_usage(&g_usbmsc.mmstart, &g_usbmsc.mmcurrent);
+}
+#else
+# define final_memory_usage(msg)
+#endif
+
+/****************************************************************************
+ * Name: usbmsc_enumerate
+ ****************************************************************************/
+
+#ifdef CONFIG_USBDEV_TRACE
+static int usbmsc_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
+ ****************************************************************************/
+
+/****************************************************************************
+ * msconn_main
+ *
+ * Description:
+ * This is the main program that configures the USB mass storage device
+ * and exports the LUN(s). If CONFIG_EXAMPLES_USBMSC_BUILTIN is defined
+ * in the NuttX configuration, then this program can be executed by
+ * entering the "msconn" command at the NSH console.
+ *
+ ****************************************************************************/
+
+int msconn_main(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_USBMSC_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_usbmsc.mshandle)
+ {
+ message("msconn_main: ERROR: Already connected\n");
+ return 1;
+ }
+#endif
+
+#ifdef CONFIG_EXAMPLES_USBMSC_DEBUGMM
+# ifdef CONFIG_CAN_PASS_STRUCTS
+ g_usbmsc.mmstart = mallinfo();
+ g_usbmsc.mmprevious = g_usbmsc.mmstart;
+# else
+ (void)mallinfo(&g_usbmsc.mmstart);
+ memcpy(&g_usbmsc.mmprevious, &g_usbmsc.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("msconn_main: Creating block drivers\n");
+ ret = usbmsc_archinitialize();
+ if (ret < 0)
+ {
+ message("msconn_main: usbmsc_archinitialize failed: %d\n", -ret);
+ return 2;
+ }
+ check_test_memory_usage("After usbmsc_archinitialize()");
+
+ /* Then exports the LUN(s) */
+
+ message("msconn_main: Configuring with NLUNS=%d\n", CONFIG_EXAMPLES_USBMSC_NLUNS);
+ ret = usbmsc_configure(CONFIG_EXAMPLES_USBMSC_NLUNS, &handle);
+ if (ret < 0)
+ {
+ message("msconn_main: usbmsc_configure failed: %d\n", -ret);
+ usbmsc_uninitialize(handle);
+ return 3;
+ }
+ message("msconn_main: handle=%p\n", handle);
+ check_test_memory_usage("After usbmsc_configure()");
+
+ message("msconn_main: Bind LUN=0 to %s\n", CONFIG_EXAMPLES_USBMSC_DEVPATH1);
+ ret = usbmsc_bindlun(handle, CONFIG_EXAMPLES_USBMSC_DEVPATH1, 0, 0, 0, false);
+ if (ret < 0)
+ {
+ message("msconn_main: usbmsc_bindlun failed for LUN 1 using %s: %d\n",
+ CONFIG_EXAMPLES_USBMSC_DEVPATH1, -ret);
+ usbmsc_uninitialize(handle);
+ return 4;
+ }
+ check_test_memory_usage("After usbmsc_bindlun()");
+
+#if CONFIG_EXAMPLES_USBMSC_NLUNS > 1
+
+ message("msconn_main: Bind LUN=1 to %s\n", CONFIG_EXAMPLES_USBMSC_DEVPATH2);
+ ret = usbmsc_bindlun(handle, CONFIG_EXAMPLES_USBMSC_DEVPATH2, 1, 0, 0, false);
+ if (ret < 0)
+ {
+ message("msconn_main: usbmsc_bindlun failed for LUN 2 using %s: %d\n",
+ CONFIG_EXAMPLES_USBMSC_DEVPATH2, -ret);
+ usbmsc_uninitialize(handle);
+ return 5;
+ }
+ check_test_memory_usage("After usbmsc_bindlun() #2");
+
+#if CONFIG_EXAMPLES_USBMSC_NLUNS > 2
+
+ message("msconn_main: Bind LUN=2 to %s\n", CONFIG_EXAMPLES_USBMSC_DEVPATH3);
+ ret = usbmsc_bindlun(handle, CONFIG_EXAMPLES_USBMSC_DEVPATH3, 2, 0, 0, false);
+ if (ret < 0)
+ {
+ message("msconn_main: usbmsc_bindlun failed for LUN 3 using %s: %d\n",
+ CONFIG_EXAMPLES_USBMSC_DEVPATH3, -ret);
+ usbmsc_uninitialize(handle);
+ return 6;
+ }
+ check_test_memory_usage("After usbmsc_bindlun() #3");
+
+#endif
+#endif
+
+ ret = usbmsc_exportluns(handle);
+ if (ret < 0)
+ {
+ message("msconn_main: usbmsc_exportluns failed: %d\n", -ret);
+ usbmsc_uninitialize(handle);
+ return 7;
+ }
+ check_test_memory_usage("After usbmsc_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_USBMSC_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("\nmsconn_main: USB TRACE DATA:\n");
+ ret = usbtrace_enumerate(usbmsc_enumerate, NULL);
+ if (ret < 0)
+ {
+ message("msconn_main: usbtrace_enumerate failed: %d\n", -ret);
+ usbmsc_uninitialize(handle);
+ return 8;
+ }
+ check_test_memory_usage("After usbtrace_enumerate()");
+# else
+ message("msconn_main: Still alive\n");
+# endif
+ }
+#elif defined(CONFIG_EXAMPLES_USBMSC_BUILTIN)
+
+ /* Return the USB mass storage device handle so it can be used by the 'misconn'
+ * command.
+ */
+
+ message("msconn_main: Connected\n");
+ g_usbmsc.mshandle = handle;
+ check_test_memory_usage("After MS connection");
+
+#else /* defined(CONFIG_DISABLE_SIGNALS) */
+
+ /* Just exit */
+
+ message("msconn_main: 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_USBMSC_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_USBMSC_BUILTIN
+int msdis_main(int argc, char *argv[])
+{
+ /* First check if the USB mass storage device is already connected */
+
+ if (!g_usbmsc.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 */
+
+ usbmsc_uninitialize(g_usbmsc.mshandle);
+ g_usbmsc.mshandle = NULL;
+ message("msdis: Disconnected\n");
+ check_test_memory_usage("After usbmsc_uninitialize()");
+
+ /* Dump debug memory usage */
+
+ final_memory_usage("Final memory usage");
+ return 0;
+}
+#endif
diff --git a/apps/examples/usbterm/Kconfig b/apps/examples/usbterm/Kconfig
new file mode 100644
index 000000000..622b7ad88
--- /dev/null
+++ b/apps/examples/usbterm/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_USBTERM
+ bool "USB serial terminal example"
+ default n
+ ---help---
+ Enable the USB serial terminal example
+
+if EXAMPLES_USBTERM
+endif
diff --git a/apps/examples/usbterm/Makefile b/apps/examples/usbterm/Makefile
new file mode 100644
index 000000000..8db1f9897
--- /dev/null
+++ b/apps/examples/usbterm/Makefile
@@ -0,0 +1,106 @@
+############################################################################
+# apps/examples/usbterm/Makefile
+#
+# Copyright (C) 2011-2012 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
+
+# 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: 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_USBTERM_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..2534c2f3c
--- /dev/null
+++ b/apps/examples/usbterm/usbterm.h
@@ -0,0 +1,181 @@
+/****************************************************************************
+ * examples/usbterm/usbterm.h
+ *
+ * Copyright (C) 2011-2012 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.
+ *
+ ****************************************************************************/
+
+#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)
+
+#ifdef CONFIG_CDCACM
+# define USBTERM_DEVNAME "/dev/ttyACM0"
+#else
+# define USBTERM_DEVNAME "/dev/ttyUSB0"
+#endif
+
+/* 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 */
+ bool peer; /* True: A peer is connected to the serial port on
+ * the remote host */
+
+ /* 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
+ ****************************************************************************/
+/****************************************************************************
+ * Name:
+ *
+ * Description:
+ * If CONFIG_EXAMPLES_USBTERM_DEVINIT is defined, then the example will
+ * call this user provided function as part of its initialization.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_EXAMPLES_USBTERM_DEVINIT
+int usbterm_devinit(void);
+#endif
+
+/****************************************************************************
+ * Name:
+ *
+ * Description:
+ * If CONFIG_EXAMPLES_USBTERM_DEVINIT is defined, then the example will
+ * call this user provided function as part of its termination sequeunce.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_EXAMPLES_USBTERM_DEVINIT
+void usbterm_devuninit(void);
+#endif
+
+#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..69301dfcd
--- /dev/null
+++ b/apps/examples/usbterm/usbterm_main.c
@@ -0,0 +1,376 @@
+/****************************************************************************
+ * examples/usbterm/usbterm_main.c
+ *
+ * Copyright (C) 2011-2012 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 <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 <apps/readline.h>
+
+#include <nuttx/usb/usbdev.h>
+#include <nuttx/usb/usbdev_trace.h>
+
+#ifdef CONFIG_CDCACM
+# include <nuttx/usb/cdcacm.h>
+#endif
+
+#ifdef CONFIG_CDCACM
+# include <nuttx/usb/pl2303.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 -- only
+ * if we know that there is someone listening at the other end. The
+ * remote side must initiate the the conversation.
+ */
+
+ if (g_usbterm.peer)
+ {
+ 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))
+ {
+ /* If we receive anything, then we can be assured that there is someone
+ * with the serial driver open on the remote host.
+ */
+
+ g_usbterm.peer = true;
+
+ /* 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: usbterm_main
+ *
+ * Description:
+ * Main entry point for the USB serial terminal example.
+ *
+ ****************************************************************************/
+
+int usbterm_main(int argc, char *argv[])
+{
+ pthread_attr_t attr;
+ int ret;
+
+ /* Initialize global data */
+
+ memset(&g_usbterm, 0, sizeof(struct usbterm_globals_s));
+
+ /* Initialization of the USB hardware may be performed by logic external to
+ * this test.
+ */
+
+#ifdef CONFIG_EXAMPLES_USBTERM_DEVINIT
+ message("usbterm_main: Performing external device initialization\n");
+ ret = usbterm_devinit();
+ if (ret != OK)
+ {
+ message("usbterm_main: usbterm_devinit failed: %d\n", ret);
+ goto errout;
+ }
+#endif
+
+ /* Initialize the USB serial driver */
+
+ message("usbterm_main: Registering USB serial driver\n");
+#ifdef CONFIG_CDCACM
+ ret = cdcacm_initialize(0, NULL);
+#else
+ ret = usbdev_serialinitialize(0);
+#endif
+ if (ret < 0)
+ {
+ message("usbterm_main: ERROR: Failed to create the USB serial device: %d\n", -ret);
+ goto errout_with_devinit;
+ }
+ message("usbterm_main: 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("usbterm_main: Opening USB serial driver\n");
+
+ g_usbterm.outstream = fopen(USBTERM_DEVNAME, "w");
+ if (g_usbterm.outstream == NULL)
+ {
+ int errcode = errno;
+ message("usbterm_main: ERROR: Failed to open " USBTERM_DEVNAME " for writing: %d\n",
+ errcode);
+
+ /* ENOTCONN means that the USB device is not yet connected */
+
+ if (errcode == ENOTCONN)
+ {
+ message("usbterm_main: Not connected. Wait and try again.\n");
+ sleep(5);
+ }
+ else
+ {
+ /* Give up on other errors */
+
+ goto errout_with_devinit;
+ }
+ }
+
+ /* 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(USBTERM_DEVNAME, "r");
+ if (g_usbterm.instream == NULL)
+ {
+ message("usbterm_main: ERROR: Failed to open " USBTERM_DEVNAME " for reading: %d\n", errno);
+ goto errout_with_outstream;
+ }
+
+ message("usbterm_main: Successfully opened the serial driver\n");
+
+ /* Start the USB term listener thread */
+
+ message("usbterm_main: Starting the listener thread\n");
+
+ ret = pthread_attr_init(&attr);
+ if (ret != OK)
+ {
+ message("usbterm_main: 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("usbterm_main: Error in thread creation: %d\n", ret);
+ goto errout_with_streams;
+ }
+
+ /* Send messages and get responses -- forever */
+
+ message("usbterm_main: Waiting for local input\n");
+ for (;;)
+ {
+ /* Display the prompt string on stdout */
+
+ fputs("usbterm> ", stdout);
+ fflush(stdout);
+
+ /* Get the next line of input */
+
+#ifdef CONFIG_EXAMPLES_USBTERM_FGETS
+ /* fgets returns NULL on end-of-file or any I/O error */
+
+ if (fgets(g_usbterm.outbuffer, CONFIG_EXAMPLES_USBTERM_BUFLEN, stdin) == NULL)
+ {
+ printf("ERROR: fgets failed: %d\n", errno);
+ return 1;
+ }
+#else
+ ret = readline(g_usbterm.outbuffer, CONFIG_EXAMPLES_USBTERM_BUFLEN, stdin, stdout);
+
+ /* Readline normally returns the number of characters read,
+ * but will return 0 on end of file or a negative value
+ * if an error occurs. Either will cause the session to
+ * terminate.
+ */
+
+ if (ret <= 0)
+ {
+ printf("ERROR: readline failed: %d\n", ret);
+ return 1;
+ }
+#endif
+ /* Is there anyone listening on the other end? */
+
+ else if (g_usbterm.peer)
+ {
+ /* Yes.. 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);
+ }
+ else
+ {
+ printf("Still waiting for remote peer. Please try again later.\n", ret);
+ }
+
+ /* 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_with_devinit:
+#ifdef CONFIG_EXAMPLES_USBTERM_DEVINIT
+ usbterm_devuninit();
+errout:
+#endif
+ message("usbterm_main: Aborting\n");
+ return 1;
+}
+
diff --git a/apps/examples/watchdog/Kconfig b/apps/examples/watchdog/Kconfig
new file mode 100644
index 000000000..18daf9327
--- /dev/null
+++ b/apps/examples/watchdog/Kconfig
@@ -0,0 +1,40 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_WATCHDOG
+ bool "Watchdog Timer example"
+ default n
+ ---help---
+ Enable the watchdog timer example
+
+if EXAMPLES_WATCHDOG
+
+config EXAMPLES_WATCHDOG_DEVPATH
+ string "Watchdog device path"
+ default "/dev/watchdog0"
+ ---help---
+ The path to the watchdog device. Default: /dev/watchdog0
+
+config CONFIG_EXAMPLES_WATCHDOG_PINGTIME
+ int "Watchdog ping time"
+ default 5000
+ ---help---
+ Time in milliseconds that the example will ping the watchdog before letting the
+ watchdog expire. Default: 5000 milliseconds.
+
+config CONFIG_EXAMPLES_WATCHDOG_PINGDELAY
+ int "Watchdog ping delay"
+ default 500
+ ---help---
+ Time delay between pings in milliseconds. Default: 500 milliseconds.
+
+config EXAMPLES_WATCHDOG_TIMEOUT
+ int "Watchdog timeout"
+ default 2000
+ ---help---
+ The watchdog timeout value in milliseconds before the watchdog timer
+ expires. Default: 2000 milliseconds.
+
+endif
diff --git a/apps/examples/watchdog/Makefile b/apps/examples/watchdog/Makefile
new file mode 100644
index 000000000..d2739dbb0
--- /dev/null
+++ b/apps/examples/watchdog/Makefile
@@ -0,0 +1,103 @@
+############################################################################
+# apps/examples/watchdog/Makefile
+#
+# Copyright (C) 2012 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
+
+# Watchdog Timer Example.
+
+ASRCS =
+CSRCS = watchdog_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 = wdog
+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:
+ $(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/examples/watchdog/watchdog.h b/apps/examples/watchdog/watchdog.h
new file mode 100644
index 000000000..dc2dea944
--- /dev/null
+++ b/apps/examples/watchdog/watchdog.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+ * examples/examples/watchdog/watchdog.h
+ *
+ * Copyright (C) 2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_EXAMPLES_WATCHDOG_WATCHDOG_H
+#define __APPS_EXAMPLES_WATCHDOG_WATCHDOG_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* CONFIG_NSH_BUILTIN_APPS - Build the WATCHDOG test as an NSH built-in
+ * function. Default: Not built! The example can only be used as an NSH
+ * built-in application
+ * CONFIG_EXAMPLES_WATCHDOG_DEVPATH - The path to the Watchdog device.
+ * Default: /dev/watchdog0
+ * CONFIG_EXAMPLES_WATCHDOG_PINGTIME - Time in milliseconds that the example
+ * will ping the watchdog before letting the watchdog expire. Default: 5000
+ * milliseconds
+ * CONFIG_EXAMPLES_WATCHDOG_PINGDELAY - Time delay between pings in
+ * milliseconds. Default: 500 milliseconds.
+ * CONFIG_EXAMPLES_WATCHDOG_TIMEOUT - The watchdog timeout value in
+ * milliseconds before the watchdog timer expires. Default: 2000
+ * milliseconds.
+ */
+
+#ifndef CONFIG_WATCHDOG
+# error "WATCHDOG device support is not enabled (CONFIG_WATCHDOG)"
+#endif
+
+#ifndef CONFIG_NSH_BUILTIN_APPS
+# warning "The WATCHDOG example only works as an NSH built-in application (CONFIG_NSH_BUILTIN_APPS)"
+#endif
+
+#ifndef CONFIG_EXAMPLES_WATCHDOG_DEVPATH
+# define CONFIG_EXAMPLES_WATCHDOG_DEVPATH "/dev/watchdog0"
+#endif
+
+#ifndef CONFIG_EXAMPLES_WATCHDOG_PINGTIME
+# define CONFIG_EXAMPLES_WATCHDOG_PINGTIME 5000
+#endif
+
+#ifndef CONFIG_EXAMPLES_WATCHDOG_PINGDELAY
+# define CONFIG_EXAMPLES_WATCHDOG_PINGDELAY 500
+#endif
+
+#ifndef CONFIG_EXAMPLES_WATCHDOG_TIMEOUT
+# define CONFIG_EXAMPLES_WATCHDOG_TIMEOUT 2000
+#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
+ ****************************************************************************/
+
+#endif /* __APPS_EXAMPLES_WATCHDOG_WATCHDOG_H */
diff --git a/apps/examples/watchdog/watchdog_main.c b/apps/examples/watchdog/watchdog_main.c
new file mode 100644
index 000000000..53099d21a
--- /dev/null
+++ b/apps/examples/watchdog/watchdog_main.c
@@ -0,0 +1,357 @@
+/****************************************************************************
+ * examples/watchdog/watchdog_main.c
+ *
+ * Copyright (C) 2012 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 <sys/ioctl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/watchdog.h>
+
+#include "watchdog.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct wdog_example_s
+{
+ uint32_t pingtime;
+ uint32_t pingdelay;
+ uint32_t timeout;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: wdog_help
+ ****************************************************************************/
+
+static void wdog_help(void)
+{
+ message("Usage: wdog [-h] [-d <pingtime] [-p <pingdelay>] [-t <timeout>]\n");
+ message("\nInitialize the watchdog to the <timeout>. Start the watchdog\n");
+ message("timer. Ping for the watchdog for <pingtime> seconds, then let it expire.\n");
+ message("\nOptions include:\n");
+ message(" [-d <pingtime>] = Selects the <delay> time in milliseconds. Default: %d\n",
+ CONFIG_EXAMPLES_WATCHDOG_PINGTIME);
+ message(" [-p <pingdelay] = Time delay between pings in milliseconds. Default: %d\n",
+ CONFIG_EXAMPLES_WATCHDOG_PINGDELAY);
+ message(" [-t timeout] = Time in milliseconds that the example will ping the watchdog\n");
+ message(" before letting the watchdog expire. Default: %d\n",
+ CONFIG_EXAMPLES_WATCHDOG_TIMEOUT);
+ message(" [-h] = Shows this message and exits\n");
+}
+
+/****************************************************************************
+ * Name: arg_string
+ ****************************************************************************/
+
+static 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
+ ****************************************************************************/
+
+static 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: parse_args
+ ****************************************************************************/
+
+static void parse_args(FAR struct wdog_example_s *wdog, int argc, FAR char **argv)
+{
+ FAR char *ptr;
+ long value;
+ int index;
+ int nargs;
+
+ wdog->pingtime = CONFIG_EXAMPLES_WATCHDOG_PINGTIME;
+ wdog->pingdelay = CONFIG_EXAMPLES_WATCHDOG_PINGDELAY;
+ wdog->timeout = CONFIG_EXAMPLES_WATCHDOG_TIMEOUT;
+
+ for (index = 1; index < argc; )
+ {
+ ptr = argv[index];
+ if (ptr[0] != '-')
+ {
+ message("Invalid options format: %s\n", ptr);
+ exit(EXIT_SUCCESS);
+ }
+
+ switch (ptr[1])
+ {
+ case 'd':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 1)
+ {
+ message("Ping delay out of range: %ld\n", value);
+ exit(EXIT_FAILURE);
+ }
+
+ wdog->pingdelay = (uint32_t)value;
+ index += nargs;
+ break;
+
+ case 'p':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 1 || value > 99)
+ {
+ message("Ping time out of range: %ld\n", value);
+ exit(EXIT_FAILURE);
+ }
+
+ wdog->pingtime = (uint8_t)value;
+ index += nargs;
+ break;
+
+ case 't':
+ nargs = arg_decimal(&argv[index], &value);
+ if (value < 1 || value > INT_MAX)
+ {
+ message("Duration out of range: %ld\n", value);
+ exit(EXIT_FAILURE);
+ }
+
+ wdog->timeout = (int)value;
+ index += nargs;
+ break;
+
+ case 'h':
+ wdog_help();
+ exit(EXIT_SUCCESS);
+
+ default:
+ message("Unsupported option: %s\n", ptr);
+ wdog_help();
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: wdog_main
+ ****************************************************************************/
+
+int wdog_main(int argc, char *argv[])
+{
+ struct wdog_example_s wdog;
+#ifdef CONFIG_DEBUG_WATCHDOG
+ struct watchdog_status_s status;
+#endif
+ long elapsed;
+ int fd;
+ int ret;
+
+ /* Parse the command line */
+
+ parse_args(&wdog, argc, argv);
+
+ /* Initialization of the WATCHDOG hardware is performed by logic external to
+ * this test.
+ */
+
+ ret = up_wdginitialize();
+ if (ret != OK)
+ {
+ message("wdog_main: up_wdginitialize failed: %d\n", ret);
+ goto errout;
+ }
+
+ /* Open the watchdog device for reading */
+
+ fd = open(CONFIG_EXAMPLES_WATCHDOG_DEVPATH, O_RDONLY);
+ if (fd < 0)
+ {
+ message("wdog_main: open %s failed: %d\n",
+ CONFIG_EXAMPLES_WATCHDOG_DEVPATH, errno);
+ goto errout;
+ }
+
+ /* Set the watchdog timeout */
+
+ ret = ioctl(fd, WDIOC_SETTIMEOUT, (unsigned long)wdog.timeout);
+ if (ret < 0)
+ {
+ message("wdog_main: ioctl(WDIOC_SETTIMEOUT) failed: %d\n", errno);
+ goto errout_with_dev;
+ }
+
+ /* Then start the watchdog timer. */
+
+ ret = ioctl(fd, WDIOC_START, 0);
+ if (ret < 0)
+ {
+ message("wdog_main: ioctl(WDIOC_START) failed: %d\n", errno);
+ goto errout_with_dev;
+ }
+
+ /* Then ping */
+
+ for (elapsed = 0; elapsed < wdog.pingtime; elapsed += wdog.pingdelay)
+ {
+ /* Sleep for the requested amount of time */
+
+ usleep(wdog.pingdelay * 1000);
+
+ /* Show watchdog status. Only if debug is enabled because this
+ * could interfere with the timer.
+ */
+
+#ifdef CONFIG_DEBUG_WATCHDOG
+ ret = ioctl(fd, WDIOC_GETSTATUS, (unsigned long)&status);
+ if (ret < 0)
+ {
+ message("wdog_main: ioctl(WDIOC_GETSTATUS) failed: %d\n", errno);
+ goto errout_with_dev;
+ }
+ message("wdog_main: flags=%08x timeout=%d timeleft=%d\n",
+ status.flags, status.timeout, status.timeleft);
+#endif
+
+ /* Then ping */
+
+ ret = ioctl(fd, WDIOC_KEEPALIVE, 0);
+ if (ret < 0)
+ {
+ message("wdog_main: ioctl(WDIOC_KEEPALIVE) failed: %d\n", errno);
+ goto errout_with_dev;
+ }
+
+ message(" ping elapsed=%ld\n", elapsed);
+ msgflush();
+ }
+
+ /* Then stop pinging */
+
+ for (; ; elapsed += wdog.pingdelay)
+ {
+ /* Sleep for the requested amount of time */
+
+ usleep(wdog.pingdelay * 1000);
+
+ /* Show watchdog status. Only if debug is enabled because this
+ * could interfere with the timer.
+ */
+
+#ifdef CONFIG_DEBUG_WATCHDOG
+ ret = ioctl(fd, WDIOC_GETSTATUS, (unsigned long)&status);
+ if (ret < 0)
+ {
+ message("wdog_main: ioctl(WDIOC_GETSTATUS) failed: %d\n", errno);
+ goto errout_with_dev;
+ }
+ message("wdog_main: flags=%08x timeout=%d timeleft=%d\n",
+ status.flags, status.timeout, status.timeleft);
+#endif
+
+ message(" NO ping elapsed=%ld\n", elapsed);
+ msgflush();
+ }
+
+ /* We should not get here */
+
+ ret = ioctl(fd, WDIOC_STOP, 0);
+ if (ret < 0)
+ {
+ message("wdog_main: ioctl(WDIOC_STOP) failed: %d\n", errno);
+ goto errout_with_dev;
+ }
+
+ close(fd);
+ msgflush();
+ return OK;
+
+errout_with_dev:
+ close(fd);
+errout:
+ msgflush();
+ return ERROR;
+}
diff --git a/apps/examples/wget/Kconfig b/apps/examples/wget/Kconfig
new file mode 100644
index 000000000..f7a1927f3
--- /dev/null
+++ b/apps/examples/wget/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_WGET
+ bool "wget example"
+ default n
+ ---help---
+ Enable the wget example
+
+if EXAMPLES_WGET
+endif
diff --git a/apps/examples/wget/Makefile b/apps/examples/wget/Makefile
new file mode 100644
index 000000000..7771619a5
--- /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 <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
+
+# 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..5d746441a
--- /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 <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.
+#
+############################################################################
+
+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..b0e65b505
--- /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 <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 <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 100644
index 000000000..e9860c22d
--- /dev/null
+++ b/apps/examples/wget/hostdefs.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+ * examples/wget/hostdefs.h
+ *
+ * Copyright (C) 2009 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.
+ *
+ *****************************************************************************/
+
+#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..5c5c65665
--- /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 <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 <unistd.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <nuttx/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
+ ****************************************************************************/
+
+/****************************************************************************
+ * wget_main
+ ****************************************************************************/
+
+int wget_main(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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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/Kconfig b/apps/examples/wlan/Kconfig
new file mode 100644
index 000000000..7f8fb526a
--- /dev/null
+++ b/apps/examples/wlan/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_WLAN
+ bool "WLAN example"
+ default n
+ ---help---
+ Enable the WLAN example
+
+if EXAMPLES_WLAN
+endif
diff --git a/apps/examples/wlan/Makefile b/apps/examples/wlan/Makefile
new file mode 100644
index 000000000..88b1e3e2a
--- /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 <gnutt@nuttx.org>
+# 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 100644
index 000000000..dcb8c770a
--- /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 <gnutt@nuttx.org>
+ * 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 <nuttx/net/uip/uip.h>
+#include <nuttx/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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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: wlan_main
+ ****************************************************************************/
+
+int wlan_main(int argc, char *argv[])
+{
+ pid_t pid;
+ int ret;
+
+ /* First, register all of the USB host Wireless LAN drivers */
+
+ printf("wlan_main: Register drivers\n");
+ ret = usbhost_wlaninit();
+ if (ret != OK)
+ {
+ printf("wlan_main: Failed to register the WLAN driver\n");
+ }
+
+ /* Then get an instance of the USB host interface */
+
+ printf("wlan_main: Initialize USB host WLAN driver\n");
+ g_drvr = usbhost_initialize(0);
+ if (g_drvr)
+ {
+ /* Start a thread to handle device connection. */
+
+ printf("wlan_main: 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/examples/xmlrpc/Kconfig b/apps/examples/xmlrpc/Kconfig
new file mode 100644
index 000000000..80ee5a225
--- /dev/null
+++ b/apps/examples/xmlrpc/Kconfig
@@ -0,0 +1,46 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config EXAMPLES_XMLRPC
+ bool "XML RPC example"
+ default n
+ depends on NET_TCP && !DISABLE_POLL
+ select NETUTILS_XMLRPC
+ ---help---
+ An example for the netutils/xmlrpc library.
+ This example implements a lightweight HTTP server and uses the xmlrpc lib
+ for parsing xml remote procedure calls.
+
+config EXAMPLES_XMLRPC_BUFFERSIZE
+ int "HTTP buffer size"
+ default 1024
+ depends on EXAMPLES_XMLRPC
+
+config EXAMPLES_XMLRPC_DHCPC
+ bool "DHCP Client"
+ default n
+ depends on EXAMPLES_XMLRPC && !NSH_BUILTIN_APPS
+ select NETUTILS_DHCPC
+ select NETUTILS_RESOLV
+
+config EXAMPLES_XMLRPC_NOMAC
+ bool "Use Canned MAC Address"
+ default n
+ depends on EXAMPLES_XMLRPC && !NSH_BUILTIN_APPS
+
+config EXAMPLES_XMLRPC_IPADDR
+ hex "Target IP address"
+ default 0x0a000002
+ depends on EXAMPLES_XMLRPC && !NSH_BUILTIN_APPS && !EXAMPLES_XMLRPC_DHCPC
+
+config EXAMPLES_XMLRPC_DRIPADDR
+ hex "Default Router IP address (Gateway)"
+ default 0x0a000001
+ depends on EXAMPLES_XMLRPC && !NSH_BUILTIN_APPS
+
+config EXAMPLES_XMLRPC_NETMASK
+ hex "Network Mask"
+ default 0xffffff00
+ depends on EXAMPLES_XMLRPC && !NSH_BUILTIN_APPS
diff --git a/apps/examples/xmlrpc/Makefile b/apps/examples/xmlrpc/Makefile
new file mode 100644
index 000000000..9fa03bf7e
--- /dev/null
+++ b/apps/examples/xmlrpc/Makefile
@@ -0,0 +1,106 @@
+############################################################################
+# apps/examples/xmlrpc/Makefile
+#
+# Copyright (C) 2012 Max Holtzberg. All rights reserved.
+# Copyright (C) 2008, 2010-2012 Gregory Nutt. All rights reserved.
+#
+# Authors: Max Holtzberg <mh@uvc.de>
+# 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
+
+# XML RPC built-in application info
+
+APPNAME = xmlrpc
+PRIORITY = SCHED_PRIORITY_DEFAULT
+STACKSIZE = 2048
+
+ASRCS =
+CSRCS = xmlrpc_main.c calls.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:
+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/xmlrpc/calls.c b/apps/examples/xmlrpc/calls.c
new file mode 100644
index 000000000..bda164f4d
--- /dev/null
+++ b/apps/examples/xmlrpc/calls.c
@@ -0,0 +1,122 @@
+/****************************************************************************
+ * apps/examples/xmlrpc/calls.c
+ *
+ * Copyright (C) 2012 Max Holtzberg. All rights reserved.
+ * Author: Max Holtzberg <mh@uvc.de>
+ *
+ * Based on the embeddable lightweight XML-RPC server code discussed
+ * in the article at: http://www.drdobbs.com/web-development/\
+ * an-embeddable-lightweight-xml-rpc-server/184405364
+ *
+ * Copyright (c) 2002 Cogito LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, is hereby granted without fee provided
+ * that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright 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 Cogito LLC nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COGITO LLC AND CONTRIBUTERS 'AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COGITO LLC
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARAY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <apps/netutils/xmlrpc.h>
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int calls_get_device_stats(struct xmlrpc_s *xmlcall);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+struct xmlrpc_entry_s get_device_stats =
+{
+ .name = "get_device_stats",
+ .func = calls_get_device_stats
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int calls_get_device_stats(struct xmlrpc_s *xmlcall)
+{
+ char username[80], password[80];
+ char lastCommand[80], curState[80];
+ int request = 0, status, ret;
+
+ do
+ {
+ ret = xmlrpc_getstring(xmlcall, username);
+ if (ret != XMLRPC_NO_ERROR)
+ {
+ break;
+ }
+
+ ret = xmlrpc_getstring(xmlcall, password);
+ if (ret != XMLRPC_NO_ERROR)
+ {
+ break;
+ }
+
+ ret = xmlrpc_getinteger(xmlcall, &request);
+ if (ret != XMLRPC_NO_ERROR)
+ {
+ break;
+ }
+ }
+ while (0);
+
+ if (ret == XMLRPC_NO_ERROR)
+ {
+ /* Dummy up some data... */
+
+ status = 1;
+ strcpy(lastCommand, "reboot");
+ strcpy(curState, "Normal Operation");
+
+ ret = xmlrpc_buildresponse(xmlcall, "{iss}",
+ "status", status,
+ "lastCommand", lastCommand,
+ "currentState", curState);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void calls_register(void)
+{
+ xmlrpc_register(&get_device_stats);
+}
diff --git a/apps/examples/xmlrpc/xmlrpc_main.c b/apps/examples/xmlrpc/xmlrpc_main.c
new file mode 100644
index 000000000..5f5ce5f06
--- /dev/null
+++ b/apps/examples/xmlrpc/xmlrpc_main.c
@@ -0,0 +1,419 @@
+/****************************************************************************
+ * apps/examples/xmlrpc/xmlrpc_main.c
+ *
+ * Copyright (C) 2012 Max Holtzberg. All rights reserved.
+ * Author: Max Holtzberg <mh@uvc.de>
+ *
+ * Based on the embeddable lightweight XML-RPC server code discussed
+ * in the article at: http://www.drdobbs.com/web-development/\
+ * an-embeddable-lightweight-xml-rpc-server/184405364
+ *
+ * Copyright (c) 2002 Cogito LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, is hereby granted without fee provided
+ * that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright 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 Cogito LLC nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COGITO LLC AND CONTRIBUTERS 'AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COGITO LLC
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARAY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************/
+
+/*
+ * Lightweight Embedded XML-RPC Server main
+ *
+ * mtj@cogitollc.com
+ *
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <debug.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <nuttx/net/uip/uip.h>
+#include <nuttx/net/uip/uip-arp.h>
+
+#include <apps/netutils/uiplib.h>
+#include <apps/netutils/xmlrpc.h>
+
+#ifdef CONFIG_EXAMPLES_XMLRPC_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_EXAMPLES_XMLRPC_DHCPC
+# include <apps/netutils/resolv.h>
+# include <apps/netutils/dhcpc.h>
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const char *notimplemented = { "HTTP/1.1 501 Not Implemented\n\n" };
+static const char *separator = { "\015\012\015\012" };
+
+/****************************************************************************
+ * External Function Prototypes
+ ****************************************************************************/
+
+extern void calls_register(void);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: xmlrpc_findbody
+ *
+ * Description:
+ * Find the message body of an HTTP Request Message
+ *
+ ****************************************************************************/
+
+static char *xmlrpc_findbody(char *buf)
+{
+ char *temp;
+
+ temp = strstr(buf, separator);
+
+ if (temp == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ return temp + 4;
+ }
+}
+
+/****************************************************************************
+ * Name: xmlrpc_getheader
+ *
+ * Description:
+ * Find the HTTP header and return it's value.
+ *
+ ****************************************************************************/
+
+static int xmlrpc_getheader(char *buffer, char *header, char *value, int size)
+{
+ char *temp;
+ int i = 0;
+
+ temp = strstr(buffer, header);
+ if (temp)
+ {
+ /* Skip the header element */
+
+ temp += strlen(header);
+
+ /* Skip any white-space */
+
+ while (*temp == ' ')
+ {
+ temp++;
+ }
+
+ /* Copy the rest to the value parameter */
+
+ while ((*temp != ' ') && (*temp != '\n') && (i < size))
+ {
+ value[i++] = *temp++;
+ }
+
+ value[i] = 0;
+ return i;
+ }
+
+ return -1;
+}
+
+/****************************************************************************
+ * Name: xmlrpc_handler
+ *
+ * Description:
+ * Parse and handle the current HTTP request message.
+ *
+ ****************************************************************************/
+
+static void xmlrpc_handler(int fd)
+{
+ fd_set rfds;
+ struct timeval tv;
+ int ret, len, max = 0, loadlen = -1;
+ char buffer[CONFIG_EXAMPLES_XMLRPC_BUFFERSIZE] = { 0 };
+ char value[CONFIG_XMLRPC_STRINGSIZE + 1];
+ char *temp;
+
+ /* Read in the Request Header */
+
+ do
+ {
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ ndbg("[%d] select...\n", fd);
+ ret = select(fd + 1, &rfds, NULL, NULL, &tv);
+ ndbg("[%d] data ready\n", fd);
+
+ if (ret > 0)
+ {
+ if (FD_ISSET(fd, &rfds))
+ {
+ len = recv(fd, &buffer[max], 1024, 0);
+ ndbg("[%d] %d bytes received\n", fd, len);
+
+ if (len > 0)
+ {
+ max += len;
+ buffer[max] = 0;
+
+ ret = xmlrpc_getheader(buffer, "Content-Length:", value,
+ CONFIG_EXAMPLES_XMLRPC_BUFFERSIZE);
+ if (ret > 0)
+ loadlen = atoi(value);
+ }
+ else
+ {
+ ret = -1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Timeout... */
+
+ ndbg("[%d] timeout\n", fd);
+ ret = -1;
+ break;
+ }
+
+ temp = strstr(buffer, separator);
+
+ if (temp)
+ {
+ if (strlen(temp) - 4 == loadlen)
+ break;
+ }
+
+ }
+ while (1);
+
+ /* Determine request */
+
+ if (!strncmp(buffer, "POST", 4))
+ {
+ temp = xmlrpc_findbody(buffer);
+ xmlrpc_parse(fd, temp);
+ }
+ else
+ {
+ write(fd, notimplemented, strlen(notimplemented));
+ }
+}
+
+/****************************************************************************
+ * Name: xmlrpc_netinit
+ *
+ * Description:
+ * Setup network configuration.
+ *
+ ****************************************************************************/
+
+static int xmlrpc_netinit(void)
+{
+ /* If this task is excecutated as an NSH built-in function, then the network
+ * has already been configured by NSH's start-up logic.
+ */
+
+#ifndef CONFIG_NSH_BUILTIN_APPS
+ struct in_addr addr;
+#if defined(CONFIG_EXAMPLES_XMLRPC_DHCPC) || defined(CONFIG_EXAMPLES_XMLRPC_NOMAC)
+ uint8_t mac[IFHWADDRLEN];
+#endif
+#ifdef CONFIG_EXAMPLES_XMLRPC_DHCPC
+ void *handle;
+#endif
+
+/* Many embedded network interfaces must have a software assigned MAC */
+
+#ifdef CONFIG_EXAMPLES_XMLRPC_NOMAC
+ mac[0] = 0x00;
+ mac[1] = 0xe0;
+ mac[2] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ uip_setmacaddr("eth0", mac);
+#endif
+
+ /* Set up our host address */
+
+#ifdef CONFIG_EXAMPLES_XMLRPC_DHCPC
+ addr.s_addr = 0;
+#else
+ addr.s_addr = HTONL(CONFIG_EXAMPLES_XMLRPC_IPADDR);
+#endif
+ uip_sethostaddr("eth0", &addr);
+
+ /* Set up the default router address */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLES_XMLRPC_DRIPADDR);
+ uip_setdraddr("eth0", &addr);
+
+ /* Setup the subnet mask */
+
+ addr.s_addr = HTONL(CONFIG_EXAMPLES_XMLRPC_NETMASK);
+ uip_setnetmask("eth0", &addr);
+
+#ifdef CONFIG_EXAMPLES_XMLRPC_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 /* CONFIG_EXAMPLES_XMLRPC_DHCPC */
+#endif /* CONFIG_NSH_BUILTIN_APPS */
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: xmlrpc_main
+ *
+ * Description:
+ * The embedded HTTP server main
+ *
+ ****************************************************************************/
+
+int xmlrpc_main(int argc, char *argv[])
+{
+ int listenfd, connfd, on = 1;
+ socklen_t clilen;
+ struct sockaddr_in cliaddr, servaddr;
+
+ if (xmlrpc_netinit() < 0)
+ {
+ ndbg("Could not initialize the network interface\n");
+ return ERROR;
+ }
+
+ /* Register RPC functions. */
+
+ calls_register();
+
+ listenfd = socket(AF_INET, SOCK_STREAM, 0);
+
+ setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+ bzero((void *)&servaddr, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(80);
+
+ bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
+
+ listen(listenfd, 5);
+
+ for (;;)
+ {
+ clilen = sizeof(cliaddr);
+ connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
+ if (connfd <= 0)
+ {
+ break;
+ }
+ ndbg("Connection accepted: %d\n", connfd);
+
+ xmlrpc_handler(connfd);
+ close(connfd);
+ ndbg("[%d] connection closed\n", connfd);
+ }
+
+ close(listenfd);
+ return (0);
+}
diff --git a/apps/graphics/Kconfig b/apps/graphics/Kconfig
new file mode 100644
index 000000000..09d3b5491
--- /dev/null
+++ b/apps/graphics/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config TIFF
+ bool "TIFF file generation utility"
+ default n
+ ---help---
+ Enable support for the TIFF file generation program.
+
+if TIFF
+endif
diff --git a/apps/graphics/Make.defs b/apps/graphics/Make.defs
new file mode 100644
index 000000000..96153a6b5
--- /dev/null
+++ b/apps/graphics/Make.defs
@@ -0,0 +1,40 @@
+############################################################################
+# apps/graphics/Make.defs
+# Adds selected applications to apps/ build
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_TIFF),y)
+CONFIGURED_APPS += graphics/tiff
+endif
+
diff --git a/apps/graphics/Makefile b/apps/graphics/Makefile
new file mode 100644
index 000000000..ddd26e536
--- /dev/null
+++ b/apps/graphics/Makefile
@@ -0,0 +1,72 @@
+############################################################################
+# apps/graphics/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 = 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..af487c1a9
--- /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 <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
+
+# 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..7b5c4fb8f
--- /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 <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 <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..abae79b63
--- /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 <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 <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..ddd5fc29d
--- /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 <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 <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->tmpfile2, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (info->tmp2fd < 0)
+ {
+ gdbg("Failed to open %s for reading/writing: %d\n", info->tmpfile2, 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..c7226e04d
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..33886d796
--- /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 <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 <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..520128203
--- /dev/null
+++ b/apps/include/apps.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+ * apps/include/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 __APPS_INCLUDE_APPS_H
+#define __APPS_INCLUDE_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 /* __APPS_INCLUDE_APPS_H */
diff --git a/apps/include/ftpc.h b/apps/include/ftpc.h
new file mode 100644
index 000000000..f9a73676a
--- /dev/null
+++ b/apps/include/ftpc.h
@@ -0,0 +1,225 @@
+/****************************************************************************
+ * apps/include/ftpc.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#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/modbus/mb.h b/apps/include/modbus/mb.h
new file mode 100644
index 000000000..be7c0df90
--- /dev/null
+++ b/apps/include/modbus/mb.h
@@ -0,0 +1,418 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mb.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_H
+#define _MB_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <termios.h>
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+
+#include "mbport.h"
+#include "mbproto.h"
+
+/*! \defgroup modbus Modbus
+ * \code #include "mb.h" \endcode
+ *
+ * This module defines the interface for the application. It contains
+ * the basic functions and types required to use the Modbus protocol stack.
+ * A typical application will want to call eMBInit() first. If the device
+ * is ready to answer network requests it must then call eMBEnable() to activate
+ * the protocol stack. In the main loop the function eMBPoll() must be called
+ * periodically. The time interval between pooling depends on the configured
+ * Modbus timeout. If an RTOS is available a separate task should be created
+ * and the task should always call the function eMBPoll().
+ *
+ * \code
+ * // Initialize protocol stack in RTU mode for a slave with address 10 = 0x0A
+ * eMBInit( MB_RTU, 0x0A, 38400, MB_PAR_EVEN );
+ * // Enable the Modbus Protocol Stack.
+ * eMBEnable( );
+ * for( ;; )
+ * {
+ * // Call the main polling loop of the Modbus protocol stack.
+ * eMBPoll( );
+ * ...
+ * }
+ * \endcode
+ */
+
+/* ----------------------- Defines ------------------------------------------*/
+
+/*! \ingroup modbus
+ * \brief Use the default Modbus TCP port (502)
+ */
+#define MB_TCP_PORT_USE_DEFAULT 0
+
+/* ----------------------- Type definitions ---------------------------------*/
+
+/*! \ingroup modbus
+ * \brief Modbus serial transmission modes (RTU/ASCII).
+ *
+ * Modbus serial supports two transmission modes. Either ASCII or RTU. RTU
+ * is faster but has more hardware requirements and requires a network with
+ * a low jitter. ASCII is slower and more reliable on slower links (E.g. modems)
+ */
+ typedef enum
+{
+ MB_RTU, /*!< RTU transmission mode. */
+ MB_ASCII, /*!< ASCII transmission mode. */
+ MB_TCP /*!< TCP mode. */
+} eMBMode;
+
+/*! \ingroup modbus
+ * \brief If register should be written or read.
+ *
+ * This value is passed to the callback functions which support either
+ * reading or writing register values. Writing means that the application
+ * registers should be updated and reading means that the modbus protocol
+ * stack needs to know the current register values.
+ *
+ * \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and
+ * eMBRegInputCB( ).
+ */
+typedef enum
+{
+ MB_REG_READ, /*!< Read register values and pass to protocol stack. */
+ MB_REG_WRITE /*!< Update register values. */
+} eMBRegisterMode;
+
+/*! \ingroup modbus
+ * \brief Errorcodes used by all function in the protocol stack.
+ */
+typedef enum
+{
+ MB_ENOERR, /*!< no error. */
+ MB_ENOREG, /*!< illegal register address. */
+ MB_EINVAL, /*!< illegal argument. */
+ MB_EPORTERR, /*!< porting layer error. */
+ MB_ENORES, /*!< insufficient resources. */
+ MB_EIO, /*!< I/O error. */
+ MB_EILLSTATE, /*!< protocol stack in illegal state. */
+ MB_ETIMEDOUT /*!< timeout error occurred. */
+} eMBErrorCode;
+
+/* ----------------------- Function prototypes ------------------------------*/
+/*! \ingroup modbus
+ * \brief Initialize the Modbus protocol stack.
+ *
+ * This functions initializes the ASCII or RTU module and calls the
+ * init functions of the porting layer to prepare the hardware. Please
+ * note that the receiver is still disabled and no Modbus frames are
+ * processed until eMBEnable( ) has been called.
+ *
+ * \param eMode If ASCII or RTU mode should be used.
+ * \param ucSlaveAddress The slave address. Only frames sent to this
+ * address or to the broadcast address are processed.
+ * \param ucPort The port to use. E.g. 1 for COM1 on windows. This value
+ * is platform dependent and some ports simply choose to ignore it.
+ * \param ulBaudRate The baudrate. E.g. B19200. Supported baudrates depend
+ * on the porting layer.
+ * \param eParity Parity used for serial transmission.
+ *
+ * \return If no error occurs the function returns eMBErrorCode::MB_ENOERR.
+ * The protocol is then in the disabled state and ready for activation
+ * by calling eMBEnable( ). Otherwise one of the following error codes
+ * is returned:
+ * - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
+ * slave addresses are in the range 1 - 247.
+ * - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
+ */
+eMBErrorCode eMBInit( eMBMode eMode, uint8_t ucSlaveAddress,
+ uint8_t ucPort, speed_t ulBaudRate, eMBParity eParity );
+
+/*! \ingroup modbus
+ * \brief Initialize the Modbus protocol stack for Modbus TCP.
+ *
+ * This function initializes the Modbus TCP Module. Please note that
+ * frame processing is still disabled until eMBEnable( ) is called.
+ *
+ * \param usTCPPort The TCP port to listen on.
+ * \return If the protocol stack has been initialized correctly the function
+ * returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
+ * codes is returned:
+ * - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
+ * slave addresses are in the range 1 - 247.
+ * - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
+ */
+eMBErrorCode eMBTCPInit( uint16_t usTCPPort );
+
+/*! \ingroup modbus
+ * \brief Release resources used by the protocol stack.
+ *
+ * This function disables the Modbus protocol stack and release all
+ * hardware resources. It must only be called when the protocol stack
+ * is disabled.
+ *
+ * \note Note all ports implement this function. A port which wants to
+ * get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
+ *
+ * \return If the resources where released it return eMBErrorCode::MB_ENOERR.
+ * If the protocol stack is not in the disabled state it returns
+ * eMBErrorCode::MB_EILLSTATE.
+ */
+eMBErrorCode eMBClose( void );
+
+/*! \ingroup modbus
+ * \brief Enable the Modbus protocol stack.
+ *
+ * This function enables processing of Modbus frames. Enabling the protocol
+ * stack is only possible if it is in the disabled state.
+ *
+ * \return If the protocol stack is now in the state enabled it returns
+ * eMBErrorCode::MB_ENOERR. If it was not in the disabled state it
+ * return eMBErrorCode::MB_EILLSTATE.
+ */
+eMBErrorCode eMBEnable( void );
+
+/*! \ingroup modbus
+ * \brief Disable the Modbus protocol stack.
+ *
+ * This function disables processing of Modbus frames.
+ *
+ * \return If the protocol stack has been disabled it returns
+ * eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns
+ * eMBErrorCode::MB_EILLSTATE.
+ */
+eMBErrorCode eMBDisable( void );
+
+/*! \ingroup modbus
+ * \brief The main pooling loop of the Modbus protocol stack.
+ *
+ * This function must be called periodically. The timer interval required
+ * is given by the application dependent Modbus slave timeout. Internally the
+ * function calls xMBPortEventGet() and waits for an event from the receiver or
+ * transmitter state machines.
+ *
+ * \return If the protocol stack is not in the enabled state the function
+ * returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns
+ * eMBErrorCode::MB_ENOERR.
+ */
+eMBErrorCode eMBPoll( void );
+
+/*! \ingroup modbus
+ * \brief Configure the slave id of the device.
+ *
+ * This function should be called when the Modbus function <em>Report Slave ID</em>
+ * is enabled (By defining CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED in .config ).
+ *
+ * \param ucSlaveID Values is returned in the <em>Slave ID</em> byte of the
+ * <em>Report Slave ID</em> response.
+ * \param xIsRunning If true the <em>Run Indicator Status</em> byte is set to 0xFF.
+ * otherwise the <em>Run Indicator Status</em> is 0x00.
+ * \param pucAdditional Values which should be returned in the <em>Additional</em>
+ * bytes of the <em> Report Slave ID</em> response.
+ * \param usAdditionalLen Length of the buffer <code>pucAdditonal</code>.
+ *
+ * \return If the static buffer defined by CONFIG_MB_FUNC_OTHER_REP_SLAVEID_BUF
+ * is too small it returns eMBErrorCode::MB_ENORES. Otherwise
+ * it returns eMBErrorCode::MB_ENOERR.
+ */
+eMBErrorCode eMBSetSlaveID( uint8_t ucSlaveID, bool xIsRunning,
+ uint8_t const *pucAdditional,
+ uint16_t usAdditionalLen );
+
+/*! \ingroup modbus
+ * \brief Registers a callback handler for a given function code.
+ *
+ * This function registers a new callback handler for a given function code.
+ * The callback handler supplied is responsible for interpreting the Modbus PDU and
+ * the creation of an appropriate response. In case of an error it should return
+ * one of the possible Modbus exceptions which results in a Modbus exception frame
+ * sent by the protocol stack.
+ *
+ * \param ucFunctionCode The Modbus function code for which this handler should
+ * be registers. Valid function codes are in the range 1 to 127.
+ * \param pxHandler The function handler which should be called in case
+ * such a frame is received. If \c NULL a previously registered function handler
+ * for this function code is removed.
+ *
+ * \return eMBErrorCode::MB_ENOERR if the handler has been installed. If no
+ * more resources are available it returns eMBErrorCode::MB_ENORES. In this
+ * case the values in config.h should be adjusted. If the argument was not
+ * valid it returns eMBErrorCode::MB_EINVAL.
+ */
+eMBErrorCode eMBRegisterCB( uint8_t ucFunctionCode,
+ pxMBFunctionHandler pxHandler );
+
+/* ----------------------- Callback -----------------------------------------*/
+
+/*! \defgroup modbus_registers Modbus Registers
+ * \code #include "mb.h" \endcode
+ * The protocol stack does not internally allocate any memory for the
+ * registers. This makes the protocol stack very small and also usable on
+ * low end targets. In addition the values don't have to be in the memory
+ * and could for example be stored in a flash.<br>
+ * Whenever the protocol stack requires a value it calls one of the callback
+ * function with the register address and the number of registers to read
+ * as an argument. The application should then read the actual register values
+ * (for example the ADC voltage) and should store the result in the supplied
+ * buffer.<br>
+ * If the protocol stack wants to update a register value because a write
+ * register function was received a buffer with the new register values is
+ * passed to the callback function. The function should then use these values
+ * to update the application register values.
+ */
+
+/*! \ingroup modbus_registers
+ * \brief Callback function used if the value of a <em>Input Register</em>
+ * is required by the protocol stack. The starting register address is given
+ * by \c usAddress and the last register is given by <tt>usAddress +
+ * usNRegs - 1</tt>.
+ *
+ * \param pucRegBuffer A buffer where the callback function should write
+ * the current value of the modbus registers to.
+ * \param usAddress The starting address of the register. Input registers
+ * are in the range 1 - 65535.
+ * \param usNRegs Number of registers the callback function must supply.
+ *
+ * \return The function must return one of the following error codes:
+ * - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
+ * Modbus response is sent.
+ * - eMBErrorCode::MB_ENOREG If the application can not supply values
+ * for registers within this range. In this case a
+ * <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
+ * - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
+ * currently not available and the application dependent response
+ * timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
+ * exception is sent as a response.
+ * - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
+ * a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
+ */
+eMBErrorCode eMBRegInputCB( uint8_t * pucRegBuffer, uint16_t usAddress,
+ uint16_t usNRegs );
+
+/*! \ingroup modbus_registers
+ * \brief Callback function used if a <em>Holding Register</em> value is
+ * read or written by the protocol stack. The starting register address
+ * is given by \c usAddress and the last register is given by
+ * <tt>usAddress + usNRegs - 1</tt>.
+ *
+ * \param pucRegBuffer If the application registers values should be updated the
+ * buffer points to the new registers values. If the protocol stack needs
+ * to now the current values the callback function should write them into
+ * this buffer.
+ * \param usAddress The starting address of the register.
+ * \param usNRegs Number of registers to read or write.
+ * \param eMode If eMBRegisterMode::MB_REG_WRITE the application register
+ * values should be updated from the values in the buffer. For example
+ * this would be the case when the Modbus master has issued an
+ * <b>WRITE SINGLE REGISTER</b> command.
+ * If the value eMBRegisterMode::MB_REG_READ the application should copy
+ * the current values into the buffer \c pucRegBuffer.
+ *
+ * \return The function must return one of the following error codes:
+ * - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
+ * Modbus response is sent.
+ * - eMBErrorCode::MB_ENOREG If the application can not supply values
+ * for registers within this range. In this case a
+ * <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
+ * - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
+ * currently not available and the application dependent response
+ * timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
+ * exception is sent as a response.
+ * - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
+ * a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
+ */
+eMBErrorCode eMBRegHoldingCB( uint8_t * pucRegBuffer, uint16_t usAddress,
+ uint16_t usNRegs, eMBRegisterMode eMode );
+
+/*! \ingroup modbus_registers
+ * \brief Callback function used if a <em>Coil Register</em> value is
+ * read or written by the protocol stack. If you are going to use
+ * this function you might use the functions xMBUtilSetBits( ) and
+ * xMBUtilGetBits( ) for working with bitfields.
+ *
+ * \param pucRegBuffer The bits are packed in bytes where the first coil
+ * starting at address \c usAddress is stored in the LSB of the
+ * first byte in the buffer <code>pucRegBuffer</code>.
+ * If the buffer should be written by the callback function unused
+ * coil values (I.e. if not a multiple of eight coils is used) should be set
+ * to zero.
+ * \param usAddress The first coil number.
+ * \param usNCoils Number of coil values requested.
+ * \param eMode If eMBRegisterMode::MB_REG_WRITE the application values should
+ * be updated from the values supplied in the buffer \c pucRegBuffer.
+ * If eMBRegisterMode::MB_REG_READ the application should store the current
+ * values in the buffer \c pucRegBuffer.
+ *
+ * \return The function must return one of the following error codes:
+ * - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
+ * Modbus response is sent.
+ * - eMBErrorCode::MB_ENOREG If the application does not map an coils
+ * within the requested address range. In this case a
+ * <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
+ * - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
+ * currently not available and the application dependent response
+ * timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
+ * exception is sent as a response.
+ * - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
+ * a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
+ */
+eMBErrorCode eMBRegCoilsCB( uint8_t * pucRegBuffer, uint16_t usAddress,
+ uint16_t usNCoils, eMBRegisterMode eMode );
+
+/*! \ingroup modbus_registers
+ * \brief Callback function used if a <em>Input Discrete Register</em> value is
+ * read by the protocol stack.
+ *
+ * If you are going to use his function you might use the functions
+ * xMBUtilSetBits( ) and xMBUtilGetBits( ) for working with bitfields.
+ *
+ * \param pucRegBuffer The buffer should be updated with the current
+ * coil values. The first discrete input starting at \c usAddress must be
+ * stored at the LSB of the first byte in the buffer. If the requested number
+ * is not a multiple of eight the remaining bits should be set to zero.
+ * \param usAddress The starting address of the first discrete input.
+ * \param usNDiscrete Number of discrete input values.
+ * \return The function must return one of the following error codes:
+ * - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
+ * Modbus response is sent.
+ * - eMBErrorCode::MB_ENOREG If no such discrete inputs exists.
+ * In this case a <b>ILLEGAL DATA ADDRESS</b> exception frame is sent
+ * as a response.
+ * - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
+ * currently not available and the application dependent response
+ * timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
+ * exception is sent as a response.
+ * - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
+ * a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
+ */
+eMBErrorCode eMBRegDiscreteCB( uint8_t * pucRegBuffer, uint16_t usAddress,
+ uint16_t usNDiscrete );
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/include/modbus/mbframe.h b/apps/include/modbus/mbframe.h
new file mode 100644
index 000000000..0f701e6e5
--- /dev/null
+++ b/apps/include/modbus/mbframe.h
@@ -0,0 +1,87 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbframe.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_FRAME_H
+#define _MB_FRAME_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+
+/*!
+ * Constants which defines the format of a modbus frame. The example is
+ * shown for a Modbus RTU/ASCII frame. Note that the Modbus PDU is not
+ * dependent on the underlying transport.
+ *
+ * <code>
+ * <------------------------ MODBUS SERIAL LINE PDU (1) ------------------->
+ * <----------- MODBUS PDU (1') ---------------->
+ * +-----------+---------------+----------------------------+-------------+
+ * | Address | Function Code | Data | CRC/LRC |
+ * +-----------+---------------+----------------------------+-------------+
+ * | | | |
+ * (2) (3/2') (3') (4)
+ *
+ * (1) ... MB_SER_PDU_SIZE_MAX = 256
+ * (2) ... MB_SER_PDU_ADDR_OFF = 0
+ * (3) ... MB_SER_PDU_PDU_OFF = 1
+ * (4) ... MB_SER_PDU_SIZE_CRC = 2
+ *
+ * (1') ... MB_PDU_SIZE_MAX = 253
+ * (2') ... MB_PDU_FUNC_OFF = 0
+ * (3') ... MB_PDU_DATA_OFF = 1
+ * </code>
+ */
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_SIZE_MAX 253 /*!< Maximum size of a PDU. */
+#define MB_PDU_SIZE_MIN 1 /*!< Function Code */
+#define MB_PDU_FUNC_OFF 0 /*!< Offset of function code in PDU. */
+#define MB_PDU_DATA_OFF 1 /*!< Offset for response data in PDU. */
+
+/* ----------------------- Prototypes 0-------------------------------------*/
+typedef void ( *pvMBFrameStart ) ( void );
+
+typedef void ( *pvMBFrameStop ) ( void );
+
+typedef eMBErrorCode( *peMBFrameReceive ) ( uint8_t * pucRcvAddress,
+ uint8_t ** pucFrame,
+ uint16_t * pusLength );
+
+typedef eMBErrorCode( *peMBFrameSend ) ( uint8_t slaveAddress,
+ const uint8_t * pucFrame,
+ uint16_t usLength );
+
+typedef void( *pvMBFrameClose ) ( void );
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/include/modbus/mbfunc.h b/apps/include/modbus/mbfunc.h
new file mode 100644
index 000000000..68ccdb1d9
--- /dev/null
+++ b/apps/include/modbus/mbfunc.h
@@ -0,0 +1,80 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbfunc.h,v 1.12 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_FUNC_H
+#define _MB_FUNC_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+#ifdef CONFIG_MB_FUNC_OTHER_REP_SLAVEID_BUF
+ eMBException eMBFuncReportSlaveID( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef CONFIG_MB_FUNC_READ_INPUT_ENABLED
+eMBException eMBFuncReadInputRegister( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef CONFIG_MB_FUNC_READ_HOLDING_ENABLED
+eMBException eMBFuncReadHoldingRegister( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef CONFIG_MB_FUNC_WRITE_HOLDING_ENABLED
+eMBException eMBFuncWriteHoldingRegister( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
+eMBException eMBFuncWriteMultipleHoldingRegister( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef CONFIG_MB_FUNC_READ_COILS_ENABLED
+eMBException eMBFuncReadCoils( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef CONFIG_MB_FUNC_WRITE_COIL_ENABLED
+eMBException eMBFuncWriteCoil( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED
+eMBException eMBFuncWriteMultipleCoils( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef CONFIG_MB_FUNC_READ_DISCRETE_INPUTS_ENABLED
+eMBException eMBFuncReadDiscreteInputs( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef CONFIG_MB_FUNC_READWRITE_HOLDING_ENABLED
+eMBException eMBFuncReadWriteMultipleHoldingRegister( uint8_t * pucFrame, uint16_t * usLen );
+#endif
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/include/modbus/mbport.h b/apps/include/modbus/mbport.h
new file mode 100644
index 000000000..9301d8c90
--- /dev/null
+++ b/apps/include/modbus/mbport.h
@@ -0,0 +1,132 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbport.h,v 1.19 2010/06/06 13:54:40 wolti Exp $
+ */
+
+#ifndef _MB_PORT_H
+#define _MB_PORT_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+
+/* ----------------------- Type definitions ---------------------------------*/
+
+typedef enum
+{
+ EV_READY, /*!< Startup finished. */
+ EV_FRAME_RECEIVED, /*!< Frame received. */
+ EV_EXECUTE, /*!< Execute function. */
+ EV_FRAME_SENT /*!< Frame sent. */
+} eMBEventType;
+
+/*! \ingroup modbus
+ * \brief Parity used for characters in serial mode.
+ *
+ * The parity which should be applied to the characters sent over the serial
+ * link. Please note that this values are actually passed to the porting
+ * layer and therefore not all parity modes might be available.
+ */
+typedef enum
+{
+ MB_PAR_NONE, /*!< No parity. */
+ MB_PAR_ODD, /*!< Odd parity. */
+ MB_PAR_EVEN /*!< Even parity. */
+} eMBParity;
+
+/* ----------------------- Supporting functions -----------------------------*/
+bool xMBPortEventInit( void );
+
+bool xMBPortEventPost( eMBEventType eEvent );
+
+bool xMBPortEventGet( /*@out@ */ eMBEventType * eEvent );
+
+/* ----------------------- Serial port functions ----------------------------*/
+
+bool xMBPortSerialInit( uint8_t ucPort, speed_t ulBaudRate,
+ uint8_t ucDataBits, eMBParity eParity );
+
+void vMBPortClose( void );
+
+void xMBPortSerialClose( void );
+
+void vMBPortSerialEnable( bool xRxEnable, bool xTxEnable );
+
+bool xMBPortSerialGetByte( int8_t * pucByte );
+
+bool xMBPortSerialPutByte( int8_t ucByte );
+
+/* ----------------------- Timers functions ---------------------------------*/
+bool xMBPortTimersInit( uint16_t usTimeOut50us );
+
+void xMBPortTimersClose( void );
+
+void vMBPortTimersEnable( void );
+
+void vMBPortTimersDisable( void );
+
+void vMBPortTimersDelay( uint16_t usTimeOutMS );
+
+/* ----------------------- Callback for the protocol stack ------------------*/
+
+/*!
+ * \brief Callback function for the porting layer when a new byte is
+ * available.
+ *
+ * Depending upon the mode this callback function is used by the RTU or
+ * ASCII transmission layers. In any case a call to xMBPortSerialGetByte()
+ * must immediately return a new character.
+ *
+ * \return <code>true</code> if a event was posted to the queue because
+ * a new byte was received. The port implementation should wake up the
+ * tasks which are currently blocked on the eventqueue.
+ */
+extern bool( *pxMBFrameCBByteReceived ) ( void );
+
+extern bool( *pxMBFrameCBTransmitterEmpty ) ( void );
+
+extern bool( *pxMBPortCBTimerExpired ) ( void );
+
+/* ----------------------- TCP port functions -------------------------------*/
+bool xMBTCPPortInit( uint16_t usTCPPort );
+
+void vMBTCPPortClose( void );
+
+void vMBTCPPortDisable( void );
+
+bool xMBTCPPortGetRequest( uint8_t **ppucMBTCPFrame, uint16_t * usTCPLength );
+
+bool xMBTCPPortSendResponse( const uint8_t *pucMBTCPFrame, uint16_t usTCPLength );
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/include/modbus/mbproto.h b/apps/include/modbus/mbproto.h
new file mode 100644
index 000000000..24b0c98e7
--- /dev/null
+++ b/apps/include/modbus/mbproto.h
@@ -0,0 +1,83 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbproto.h,v 1.14 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_PROTO_H
+#define _MB_PROTO_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_ADDRESS_BROADCAST ( 0 ) /*! Modbus broadcast address. */
+#define MB_ADDRESS_MIN ( 1 ) /*! Smallest possible slave address. */
+#define MB_ADDRESS_MAX ( 247 ) /*! Biggest possible slave address. */
+#define MB_FUNC_NONE ( 0 )
+#define MB_FUNC_READ_COILS ( 1 )
+#define MB_FUNC_READ_DISCRETE_INPUTS ( 2 )
+#define MB_FUNC_WRITE_SINGLE_COIL ( 5 )
+#define MB_FUNC_WRITE_MULTIPLE_COILS ( 15 )
+#define MB_FUNC_READ_HOLDING_REGISTER ( 3 )
+#define MB_FUNC_READ_INPUT_REGISTER ( 4 )
+#define MB_FUNC_WRITE_REGISTER ( 6 )
+#define MB_FUNC_WRITE_MULTIPLE_REGISTERS ( 16 )
+#define MB_FUNC_READWRITE_MULTIPLE_REGISTERS ( 23 )
+#define MB_FUNC_DIAG_READ_EXCEPTION ( 7 )
+#define MB_FUNC_DIAG_DIAGNOSTIC ( 8 )
+#define MB_FUNC_DIAG_GET_COM_EVENT_CNT ( 11 )
+#define MB_FUNC_DIAG_GET_COM_EVENT_LOG ( 12 )
+#define MB_FUNC_OTHER_REPORT_SLAVEID ( 17 )
+#define MB_FUNC_ERROR ( 128 )
+/* ----------------------- Type definitions ---------------------------------*/
+ typedef enum
+{
+ MB_EX_NONE = 0x00,
+ MB_EX_ILLEGAL_FUNCTION = 0x01,
+ MB_EX_ILLEGAL_DATA_ADDRESS = 0x02,
+ MB_EX_ILLEGAL_DATA_VALUE = 0x03,
+ MB_EX_SLAVE_DEVICE_FAILURE = 0x04,
+ MB_EX_ACKNOWLEDGE = 0x05,
+ MB_EX_SLAVE_BUSY = 0x06,
+ MB_EX_MEMORY_PARITY_ERROR = 0x08,
+ MB_EX_GATEWAY_PATH_FAILED = 0x0A,
+ MB_EX_GATEWAY_TGT_FAILED = 0x0B
+} eMBException;
+
+typedef eMBException( *pxMBFunctionHandler ) ( uint8_t * pucFrame, uint16_t * pusLength );
+
+typedef struct
+{
+ uint8_t ucFunctionCode;
+ pxMBFunctionHandler pxHandler;
+} xMBFunctionHandler;
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/include/modbus/mbutils.h b/apps/include/modbus/mbutils.h
new file mode 100644
index 000000000..5f17376cc
--- /dev/null
+++ b/apps/include/modbus/mbutils.h
@@ -0,0 +1,108 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbutils.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_UTILS_H
+#define _MB_UTILS_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+/*! \defgroup modbus_utils Utilities
+ *
+ * This module contains some utility functions which can be used by
+ * the application. It includes some special functions for working with
+ * bitfields backed by a character array buffer.
+ *
+ */
+/*! \addtogroup modbus_utils
+ * @{
+ */
+/*! \brief Function to set bits in a byte buffer.
+ *
+ * This function allows the efficient use of an array to implement bitfields.
+ * The array used for storing the bits must always be a multiple of two
+ * bytes. Up to eight bits can be set or cleared in one operation.
+ *
+ * \param ucByteBuf A buffer where the bit values are stored. Must be a
+ * multiple of 2 bytes. No length checking is performed and if
+ * usBitOffset / 8 is greater than the size of the buffer memory contents
+ * is overwritten.
+ * \param usBitOffset The starting address of the bits to set. The first
+ * bit has the offset 0.
+ * \param ucNBits Number of bits to modify. The value must always be smaller
+ * than 8.
+ * \param ucValues Thew new values for the bits. The value for the first bit
+ * starting at <code>usBitOffset</code> is the LSB of the value
+ * <code>ucValues</code>
+ *
+ * \code
+ * ucBits[2] = {0, 0};
+ *
+ * // Set bit 4 to 1 (read: set 1 bit starting at bit offset 4 to value 1)
+ * xMBUtilSetBits( ucBits, 4, 1, 1 );
+ *
+ * // Set bit 7 to 1 and bit 8 to 0.
+ * xMBUtilSetBits( ucBits, 7, 2, 0x01 );
+ *
+ * // Set bits 8 - 11 to 0x05 and bits 12 - 15 to 0x0A;
+ * xMBUtilSetBits( ucBits, 8, 8, 0x5A);
+ * \endcode
+ */
+void xMBUtilSetBits( uint8_t * ucByteBuf, uint16_t usBitOffset,
+ uint8_t ucNBits, uint8_t ucValues );
+
+/*! \brief Function to read bits in a byte buffer.
+ *
+ * This function is used to extract up bit values from an array. Up to eight
+ * bit values can be extracted in one step.
+ *
+ * \param ucByteBuf A buffer where the bit values are stored.
+ * \param usBitOffset The starting address of the bits to set. The first
+ * bit has the offset 0.
+ * \param ucNBits Number of bits to modify. The value must always be smaller
+ * than 8.
+ *
+ * \code
+ * uint8_t ucBits[2] = {0, 0};
+ * uint8_t ucResult;
+ *
+ * // Extract the bits 3 - 10.
+ * ucResult = xMBUtilGetBits( ucBits, 3, 8 );
+ * \endcode
+ */
+uint8_t xMBUtilGetBits( uint8_t * ucByteBuf, uint16_t usBitOffset,
+ uint8_t ucNBits );
+
+/*! @} */
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/include/netutils/dhcpc.h b/apps/include/netutils/dhcpc.h
new file mode 100644
index 000000000..a6c53dc30
--- /dev/null
+++ b/apps/include/netutils/dhcpc.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+ * apps/include/netutils/dhcpc.h
+ *
+ * Copyright (C) 2007, 2009-2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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_INCLUDE_NETUTILS_DHCPC_H
+#define __APPS_INCLUDE_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_INCLUDE_NETUTILS_DHCPC_H */
diff --git a/apps/include/netutils/dhcpd.h b/apps/include/netutils/dhcpd.h
new file mode 100644
index 000000000..f997fac30
--- /dev/null
+++ b/apps/include/netutils/dhcpd.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+ * apps/include/netutils/dhcpd.h
+ *
+ * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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_INCLUDE_NETUTILS_DHCPD_H
+#define __APPS_INCLUDE_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_INCLUDE_NETUTILS_DHCPD_H */
diff --git a/apps/include/netutils/discover.h b/apps/include/netutils/discover.h
new file mode 100644
index 000000000..c2226918d
--- /dev/null
+++ b/apps/include/netutils/discover.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+ * apps/include/netutils/discover.h
+ *
+ * Copyright (C) 2012 Max Holtzberg. All rights reserved.
+ * Author: Max Holtzberg <mh@uvc.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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_NETUTILS_DISCOVER_H
+#define __APPS_INCLUDE_NETUTILS_DISCOVER_H
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: discover_start
+ *
+ * Description:
+ * Start the discover daemon.
+ *
+ * Return:
+ * The process ID (pid) of the new discover daemon is returned on
+ * success; A negated errno is returned if the daemon was not successfully
+ * started.
+ *
+ ****************************************************************************/
+
+int discover_start(void);
+
+#endif /* __APPS_INCLUDE_NETUTILS_DISCOVER_H */
diff --git a/apps/include/netutils/ftpd.h b/apps/include/netutils/ftpd.h
new file mode 100644
index 000000000..71a2096bb
--- /dev/null
+++ b/apps/include/netutils/ftpd.h
@@ -0,0 +1,217 @@
+/****************************************************************************
+ * apps/include/netutils/ftpd.h
+ *
+ * Copyright (C) 2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_NETUTILS_FTPD_H
+#define __APPS_INCLUDE_NETUTILS_FTPD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* Required configuration settings: Of course TCP networking support is
+ * required. But here are a couple that are less obvious:
+ *
+ * CONFIG_DISABLE_PTHREAD - pthread support is required
+ * CONFIG_DISABLE_POLL - poll() support is required
+ *
+ * Other FTPD configuration options thay may be of interest:
+ *
+ * CONFIG_FTPD_VENDORID - The vendor name to use in FTP communications.
+ * Default: "NuttX"
+ * CONFIG_FTPD_SERVERID - The server name to use in FTP communications.
+ * Default: "NuttX FTP Server"
+ * CONFIG_FTPD_CMDBUFFERSIZE - The maximum size of one command. Default:
+ * 128 bytes.
+ * CONFIG_FTPD_DATABUFFERSIZE - The size of the I/O buffer for data
+ * transfers. Default: 512 bytes.
+ * CONFIG_FTPD_WORKERSTACKSIZE - The stacksize to allocate for each
+ * FTP daemon worker thread. Default: 2048 bytes.
+ */
+
+#ifdef CONFIG_DISABLE_PTHREAD
+# error "pthread support is required (CONFIG_DISABLE_PTHREAD=n)"
+#endif
+
+#ifdef CONFIG_DISABLE_POLL
+# error "poll() support is required (CONFIG_DISABLE_POLL=n)"
+#endif
+
+#ifndef CONFIG_FTPD_VENDORID
+# define CONFIG_FTPD_VENDORID "NuttX"
+#endif
+
+#ifndef CONFIG_FTPD_SERVERID
+# define CONFIG_FTPD_SERVERID "NuttX FTP Server"
+#endif
+
+#ifndef CONFIG_FTPD_CMDBUFFERSIZE
+# define CONFIG_FTPD_CMDBUFFERSIZE 128
+#endif
+
+#ifndef CONFIG_FTPD_DATABUFFERSIZE
+# define CONFIG_FTPD_DATABUFFERSIZE 512
+#endif
+
+#ifndef CONFIG_FTPD_WORKERSTACKSIZE
+# define CONFIG_FTPD_WORKERSTACKSIZE 2048
+#endif
+
+/* Interface definitions ****************************************************/
+
+#define FTPD_ACCOUNTFLAG_NONE (0)
+#define FTPD_ACCOUNTFLAG_ADMIN (1 << 0)
+#define FTPD_ACCOUNTFLAG_SYSTEM (1 << 1)
+#define FTPD_ACCOUNTFLAG_GUEST (1 << 2)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* This "handle" describes the FTP session */
+
+typedef FAR void *FTPD_SESSION;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpd_open
+ *
+ * Description:
+ * Create an instance of the FTPD server and return a handle that can be
+ * used to run the server.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * On success, a non-NULL handle is returned that can be used to reference
+ * the server instance.
+ *
+ ****************************************************************************/
+
+EXTERN FTPD_SESSION ftpd_open(void);
+
+/****************************************************************************
+ * Name: ftpd_adduser
+ *
+ * Description:
+ * Add one FTP user.
+ *
+ * Input Parameters:
+ * handle - A handle previously returned by ftpd_open
+ * accountflags - The characteristics of this user (see FTPD_ACCOUNTFLAGS_*
+ * definitions above).
+ * user - The user login name. May be NULL indicating that no login is
+ * required.
+ * passwd - The user password. May be NULL indicating that no password
+ * is required.
+ * home - The user home directory. May be NULL.
+ *
+ * Returned Value:
+ * Zero is returned on success. A negated errno value is return on
+ * failure.
+ *
+ ****************************************************************************/
+
+EXTERN int ftpd_adduser(FTPD_SESSION handle, uint8_t accountflags,
+ FAR const char *user, FAR const char *passwd,
+ FAR const char *home);
+
+/****************************************************************************
+ * Name: ftpd_session
+ *
+ * Description:
+ * Execute the FTPD server. This thread does not return until either (1)
+ * the timeout expires with no connection, (2) some other error occurs, or
+ * (2) a connection was accepted and an FTP worker thread was started to
+ * service the session. Each call to ftpd_session creates on session.
+ *
+ * Input Parameters:
+ * handle - A handle previously returned by ftpd_open
+ * timeout - A time in milliseconds to wait for a connection. If this
+ * time elapses with no connected, the -ETIMEDOUT error will be returned.
+ *
+ * Returned Value:
+ * Zero is returned if the FTP worker was started. On failure, a negated
+ * errno value is returned to indicate why the servier terminated.
+ * -ETIMEDOUT indicates that the user-provided timeout elapsed with no
+ * connection.
+ *
+ ****************************************************************************/
+
+EXTERN int ftpd_session(FTPD_SESSION handle, int timeout);
+
+/****************************************************************************
+ * Name: ftpd_close
+ *
+ * Description:
+ * Close and destroy the handle created by ftpd_open.
+ *
+ * Input Parameters:
+ * handle - A handle previously returned by ftpd_open
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+EXTERN void ftpd_close(FTPD_SESSION handle);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+#endif /* __APPS_INCLUDE_NETUTILS_FTPD_H */
diff --git a/apps/include/netutils/httpd.h b/apps/include/netutils/httpd.h
new file mode 100644
index 000000000..8ba9e2f7b
--- /dev/null
+++ b/apps/include/netutils/httpd.h
@@ -0,0 +1,185 @@
+/****************************************************************************
+ * apps/include/netutils/httpd.h
+ *
+ * Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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_INCLUDE_NETUTILS_HTTPD_H
+#define __APPS_INCLUDE_NETUTILS_HTTPD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/net/uip/uip.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef __cplusplus
+# define EXTERN extern "C"
+extern "C" {
+#else
+# define EXTERN extern
+#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_HTTPDSTACKSIZE
+# define CONFIG_NETUTILS_HTTPDSTACKSIZE 4096
+#endif
+
+#ifndef CONFIG_NETUTILS_HTTPDFSSTATS
+# define CONFIG_NETUTILS_HTTPDFSSTATS
+#endif
+
+#ifndef CONFIG_NETUTILS_HTTPDFILESTATS
+# define CONFIG_NETUTILS_HTTPDFILESTATS
+#endif
+
+#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 */
+
+#if defined(CONFIG_NETUTILS_HTTPD_MMAP) || defined(CONFIG_NETUTILS_HTTPD_SENDFILE)
+#define HTTPD_MAX_FILENAME PATH_MAX
+#else
+#define HTTPD_MAX_FILENAME 20
+#endif
+
+/****************************************************************************
+ * Public types
+ ****************************************************************************/
+
+struct httpd_fs_file
+{
+ char *data;
+ int len;
+#if defined(CONFIG_NETUTILS_HTTPD_MMAP) || defined(CONFIG_NETUTILS_HTTPD_SENDFILE)
+ int fd;
+#endif
+};
+
+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;
+};
+
+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
+ uint16_t count;
+#endif
+};
+
+struct httpd_fsdata_file_noconst
+{
+ FAR struct httpd_fsdata_file *next;
+ FAR char *name;
+ FAR char *data;
+ int len;
+#ifdef CONFIG_NETUTILS_HTTPDFSSTATS
+ uint16_t count;
+#endif
+};
+
+typedef void (*httpd_cgifunction)(struct httpd_state *, char *);
+
+struct httpd_cgi_call
+{
+ struct httpd_cgi_call *next;
+ const char *name;
+ httpd_cgifunction function;
+};
+
+/* HTTPD CGI function declaration
+ *
+ * Description:
+ * 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_register()
+ * function.
+
+ * Input Paramters:
+ *
+ * name The C variable name of the function
+ * str The string name of the function, used in the script file
+ * function A pointer to the function that implements it
+ */
+
+#define HTTPD_CGI_CALL(name, str, function) \
+static void function(struct httpd_state *, char *); \
+static struct httpd_cgi_call name = {NULL, str, function}
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+EXTERN void httpd_init(void);
+EXTERN int httpd_listen(void);
+EXTERN void httpd_cgi_register(struct httpd_cgi_call *cgi_call);
+EXTERN uint16_t httpd_fs_count(char *name);
+
+EXTERN const struct httpd_fsdata_file g_httpdfs_root[];
+EXTERN const int g_httpd_numfiles;
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __APPS_INCLUDE_NETUTILS_HTTPD_H */
diff --git a/apps/include/netutils/ipmsfilter.h b/apps/include/netutils/ipmsfilter.h
new file mode 100644
index 000000000..2dcffa4a1
--- /dev/null
+++ b/apps/include/netutils/ipmsfilter.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+ * apps/include/netutils/ipmsfilter.h
+ * User interface to add/remove IP multicast address
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_NETUTILS_IPMSFILTER_H
+#define __APPS_INCLUDE_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_INCLUDE_NETUTILS_IPMSFILTER_H */
diff --git a/apps/include/netutils/resolv.h b/apps/include/netutils/resolv.h
new file mode 100644
index 000000000..bf71e3b6e
--- /dev/null
+++ b/apps/include/netutils/resolv.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+ * apps/include/netutils/resolv.h
+ * DNS resolver code header file.
+ * Author Adam Dunkels <adam@dunkels.com>
+ *
+ * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Inspired by/based on uIP logic by Adam Dunkels:
+ *
+ * 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_INCLUDE_NETUTILS_RESOLVE_H
+#define __APPS_INCLUDE_NETUTILS_RESOLVE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/net/uip/uipopt.h>
+
+#include <netinet/in.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#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(FAR const struct in6_addr *dnsserver);
+EXTERN void resolv_getserver(FAR const struct in_addr *dnsserver);
+EXTERN int resolv_query(FAR const char *name, FAR struct sockaddr_in6 *addr);
+#else
+EXTERN void resolv_conf(FAR const struct in_addr *dnsserver);
+EXTERN void resolv_getserver(FAR struct in_addr *dnsserver);
+EXTERN int resolv_query(FAR const char *name, FAR struct sockaddr_in *addr);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __APPS_INCLUDE_NETUTILS_RESOLVE_H */
diff --git a/apps/include/netutils/smtp.h b/apps/include/netutils/smtp.h
new file mode 100644
index 000000000..1bb0cc16f
--- /dev/null
+++ b/apps/include/netutils/smtp.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+ * apps/include/netutils/smtp.h
+ * SMTP header file
+ *
+ * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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_INCLUDE_NETUTILS_SMTP_H
+#define __APPS_INCLUDE_NETUTILS_SMTP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/net/uip/uipopt.h>
+#include <nuttx/net/uip/uip.h>
+
+/****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+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);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __APPS_INCLUDE_NETUTILS_SMTP_H */
diff --git a/apps/include/netutils/telnetd.h b/apps/include/netutils/telnetd.h
new file mode 100644
index 000000000..98721c023
--- /dev/null
+++ b/apps/include/netutils/telnetd.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+ * apps/include/netutils/telnetd.h
+ *
+ * Copyright (C) 2007, 2011-2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_NETUTILS_TELNETD_H
+#define __APPS_INCLUDE_NETUTILS_TELNETD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* CONFIG_TELNETD_CONSOLE - Use the first telnet session as the default
+ * console.
+ * CONFIG_TELNETD_RXBUFFER_SIZE - The size of the telnet receive buffer.
+ * Default: 256 bytes.
+ * CONFIG_TELNETD_TXBUFFER_SIZE - The size of the telnet transmit buffer.
+ * Default: 256 bytes.
+ * CONFIG_TELNETD_DUMPBUFFER - dumping of all input/output buffers.
+ */
+
+#ifndef CONFIG_TELNETD_RXBUFFER_SIZE
+# define CONFIG_TELNETD_RXBUFFER_SIZE 256
+#endif
+
+#ifndef CONFIG_TELNETD_TXBUFFER_SIZE
+# define CONFIG_TELNETD_TXBUFFER_SIZE 256
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+ /* An instance of the struct telnetd_config_s structure must be passed to
+ * telnetd_start in order to configure the new telnet daemon.
+ */
+
+struct telnetd_config_s
+{
+ /* These fields describe the telnet daemon */
+
+ int d_port; /* The port to listen on (in network byte order) */
+ int d_priority; /* The execution priority of the telnet daemon task */
+ int d_stacksize; /* The stack size needed by the telnet daemon task */
+
+ /* These fields describe the priority of each thread created by the telnet
+ * daemon.
+ */
+
+ int t_priority; /* The execution priority of the spawned task, */
+ int t_stacksize; /* The stack size needed by the spawned task */
+ main_t t_entry; /* The entrypoint of the task to spawn when a new
+ * connection is accepted. */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: telnetd_start
+ *
+ * Description:
+ * Start the telnet daemon.
+ *
+ * Parameters:
+ * config A pointer to a configuration structure that characterizes the
+ * telnet daemon. This configuration structure may be defined
+ * on the caller's stack because it is not retained by the
+ * daemon.
+ *
+ * Return:
+ * The process ID (pid) of the new telnet daemon is returned on
+ * success; A negated errno is returned if the daemon was not successfully
+ * started.
+ *
+ ****************************************************************************/
+
+EXTERN int telnetd_start(FAR struct telnetd_config_s *config);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+#endif /* __APPS_INCLUDE_NETUTILS_TELNETD_H */
diff --git a/apps/include/netutils/tftp.h b/apps/include/netutils/tftp.h
new file mode 100644
index 000000000..276073aad
--- /dev/null
+++ b/apps/include/netutils/tftp.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+ * apps/include/netutils/tftp.h
+ *
+ * Copyright (C) 2008-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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_NETUTILS_TFTP_H
+#define __APPS_INCLUDE_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_INCLUDE_NETUTILS_TFTP_H */
diff --git a/apps/include/netutils/thttpd.h b/apps/include/netutils/thttpd.h
new file mode 100644
index 000000000..92ed7ba97
--- /dev/null
+++ b/apps/include/netutils/thttpd.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+ * apps/include/netutils/thttpd.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_NETUTILS_THTTPD_H
+#define __APPS_INCLUDE_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_INCLUDE_NETUTILS_THTTPD_H */
diff --git a/apps/include/netutils/uiplib.h b/apps/include/netutils/uiplib.h
new file mode 100644
index 000000000..b99417362
--- /dev/null
+++ b/apps/include/netutils/uiplib.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+ * apps/include/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 <gnutt@nuttx.org>
+ *
+ * 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_INCLUDE_NETUTILS_UIPLIB_H
+#define __APPS_INCLUDE_NETUTILS_UIPLIB_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <pthread.h>
+
+#include <netinet/in.h>
+#include <nuttx/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
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/* 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 int uip_listenon(uint16_t portno);
+EXTERN void uip_server(uint16_t portno, pthread_startroutine_t handler, int stacksize);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __APPS_INCLUDE_NETUTILS_UIPLIB_H */
diff --git a/apps/include/netutils/webclient.h b/apps/include/netutils/webclient.h
new file mode 100644
index 000000000..5c07f20ab
--- /dev/null
+++ b/apps/include/netutils/webclient.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+ * apps/include/netutils/webclient.h
+ * Header file for the HTTP client
+ *
+ * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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_INCLUDE_NETUTILS_WEBCLIENT_H
+#define __APPS_INCLUDE_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_INCLUDE_NETUTILS_WEBCLIENT_H */
diff --git a/apps/include/netutils/xmlrpc.h b/apps/include/netutils/xmlrpc.h
new file mode 100644
index 000000000..3136e35ef
--- /dev/null
+++ b/apps/include/netutils/xmlrpc.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+ * apps/include/netutils/xmlrpc.h
+ *
+ * Copyright (C) 2012 Max Holtzberg. All rights reserved.
+ * Author: Max Holtzberg <mh@uvc.de>
+ *
+ * Based on the embeddable lightweight XML-RPC server code discussed
+ * in the article at: http://www.drdobbs.com/web-development/\
+ * an-embeddable-lightweight-xml-rpc-server/184405364
+ *
+ * Copyright (c) 2002 Cogito LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, is hereby granted without fee provided
+ * that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright 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 Cogito LLC nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COGITO LLC AND CONTRIBUTERS 'AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COGITO LLC
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARAY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************/
+
+/*
+ * Lightweight Embedded XML-RPC Server Types and Definitions
+ *
+ * mtj@cogitollc.com
+ *
+ */
+
+#ifndef __APPS_INCLUDE_NETUTILS_XMLRPC_H
+#define __APPS_INCLUDE_NETUTILS_XMLRPC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Error definitions. */
+
+#define XMLRPC_NO_ERROR (0)
+#define XMLRPC_PARSE_ERROR (-1)
+#define XMLRPC_NO_SUCH_FUNCTION (-2)
+#define XMLRPC_UNEXPECTED_INTEGER_ARG (-3)
+#define XMLRPC_UNEXPECTED_BOOLEAN_ARG (-4)
+#define XMLRPC_UNEXPECTED_DOUBLE_ARG (-5)
+#define XMLRPC_UNEXPECTED_STRING_ARG (-6)
+#define XMLRPC_BAD_RESPONSE_ARG (-7)
+#define XMLRPC_INTERNAL_ERROR (-99)
+
+#define MAX_ARGS 10
+#define MAX_RESPONSE 2048
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct xmlrpc_arg_s
+{
+ union
+ {
+ int i;
+ char boolean;
+ double d;
+ char string[CONFIG_XMLRPC_STRINGSIZE+1];
+ } u;
+};
+
+struct xmlrpc_s
+{
+ char name[CONFIG_XMLRPC_STRINGSIZE+1];
+ struct xmlrpc_arg_s arguments[MAX_ARGS];
+ char args[MAX_ARGS];
+ int argsize;
+ int arg;
+ char response[MAX_RESPONSE];
+ int error;
+};
+
+struct xmlrpc_entry_s
+{
+ struct xmlrpc_entry_s *next;
+ int (*func)(struct xmlrpc_s*);
+ char *name;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+void xmlrpc_register(struct xmlrpc_entry_s *call);
+int xmlrpc_parse(int sock, char *buffer);
+int xmlrpc_getinteger(struct xmlrpc_s *xmlcall, int *arg);
+int xmlrpc_getbool(struct xmlrpc_s *xmlcall, int *arg);
+int xmlrpc_getdouble(struct xmlrpc_s *xmlcall, double *arg);
+int xmlrpc_getstring(struct xmlrpc_s *xmlcall, char *arg);
+int xmlrpc_buildresponse(struct xmlrpc_s *, char *, ...);
+
+#endif /* __APPS_INCLUDE_NETUTILS_XMLRPC_H */
diff --git a/apps/include/nsh.h b/apps/include/nsh.h
new file mode 100644
index 000000000..4b5a3cd31
--- /dev/null
+++ b/apps/include/nsh.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+ * apps/include/nsh.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_NSH_H
+#define __APPS_INCLUDE_NSH_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
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_initialize
+ *
+ * Description:
+ * This nterfaces is used to initialize the NuttShell (NSH).
+ * nsh_initialize() should be called one during application start-up prior
+ * to executing either nsh_consolemain() or nsh_telnetstart().
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+EXTERN void nsh_initialize(void);
+
+/****************************************************************************
+ * Name: nsh_consolemain
+ *
+ * Description:
+ * This interfaces maybe to called or started with task_start to start a
+ * single an NSH instance that operates on stdin and stdout (/dev/console).
+ * This function does not return.
+ *
+ * Input Parameters:
+ * Standard task start-up arguements. These are not used. argc may be
+ * zero and argv may be NULL.
+ *
+ * Returned Values:
+ * This function does not normally return. exit() is usually called to
+ * terminate the NSH session. This function will return in the event of
+ * an error. In that case, a nonzero value is returned (1).
+ *
+ ****************************************************************************/
+
+EXTERN int nsh_consolemain(int argc, char *argv[]);
+
+/* nsh_telnetstart() starts a telnet daemon that will allow multiple
+ * NSH connections via telnet. This function returns immediately after
+ * the daemon has been started.
+ */
+
+EXTERN int nsh_telnetstart(void);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __APPS_INCLUDE_NSH_H */
diff --git a/apps/include/readline.h b/apps/include/readline.h
new file mode 100644
index 000000000..647778210
--- /dev/null
+++ b/apps/include/readline.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+ * apps/include/readline.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_READLINE_H
+#define __APPS_INCLUDE_READLINE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: readline
+ *
+ * readline() reads in at most one less than 'buflen' characters from
+ * 'instream' and stores them into the buffer pointed to by 'buf'.
+ * Characters are echoed on 'outstream'. Reading stops after an EOF or a
+ * newline. If a newline is read, it is stored into the buffer. A null
+ * terminator is stored after the last character in the buffer.
+ *
+ * This version of realine assumes that we are reading and writing to
+ * a VT100 console. This will not work well if 'instream' or 'outstream'
+ * corresponds to a raw byte steam.
+ *
+ * This function is inspired by the GNU readline but is an entirely
+ * different creature.
+ *
+ * Input Parameters:
+ * buf - The user allocated buffer to be filled.
+ * buflen - the size of the buffer.
+ * instream - The stream to read characters from
+ * outstream - The stream to each characters to.
+ *
+ * Returned values:
+ * On success, the (positive) number of bytes transferred is returned.
+ * A length of zero would indicated an end of file condition. An failure,
+ * a negated errno value is returned.
+ *
+ **************************************************************************/
+
+EXTERN ssize_t readline(FAR char *buf, int buflen, FILE *instream, FILE *outstream);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __APPS_INCLUDE_READLINE_H */
diff --git a/apps/include/tiff.h b/apps/include/tiff.h
new file mode 100644
index 000000000..378af9fe0
--- /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 <gnutt@nuttx.org>
+ *
+ * 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/Kconfig b/apps/interpreters/Kconfig
new file mode 100644
index 000000000..34cbf2eee
--- /dev/null
+++ b/apps/interpreters/Kconfig
@@ -0,0 +1,21 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+comment "Interpreters"
+
+source "$APPSDIR/interpreters/ficl/Kconfig"
+
+config PCODE
+ bool "Pascal p-code interpreter"
+ default n
+ ---help---
+ Enable support for the Pascal p-code interpreter. See README file at misc/pascal
+ and also the README.txt file in the apps/interpreter directory. Use of this
+ configuration implies that you have performed the required installation of the
+ Pascal run-time code.
+
+if PCODE
+endif
+
diff --git a/apps/interpreters/Make.defs b/apps/interpreters/Make.defs
new file mode 100644
index 000000000..2fc4b26d4
--- /dev/null
+++ b/apps/interpreters/Make.defs
@@ -0,0 +1,43 @@
+############################################################################
+# apps/interpreters/Make.defs
+# Adds selected applications to apps/ build
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_PCODE),y)
+CONFIGURED_APPS += interpreters/pcode
+endif
+
+ifeq ($(CONFIG_FICL),y)
+CONFIGURED_APPS += interpreters/ficl
+endif
diff --git a/apps/interpreters/Makefile b/apps/interpreters/Makefile
new file mode 100644
index 000000000..5901fc830
--- /dev/null
+++ b/apps/interpreters/Makefile
@@ -0,0 +1,70 @@
+############################################################################
+# apps/interpreters/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 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..f33c75df1
--- /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 passhello_main 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/Kconfig b/apps/interpreters/ficl/Kconfig
new file mode 100644
index 000000000..1860a1591
--- /dev/null
+++ b/apps/interpreters/ficl/Kconfig
@@ -0,0 +1,16 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config FICL
+ bool "Ficl Forth interpreter"
+ default n
+ ---help---
+ Enable support for the Ficl interpreter interpreter. See README.txt file in the
+ apps/interpreters/ficl directory. Use of this configuration assumes
+ that you have performed the required installation of the Ficl run-time code.
+
+if FICL
+endif
+
diff --git a/apps/interpreters/ficl/Makefile b/apps/interpreters/ficl/Makefile
new file mode 100644
index 000000000..fb953964e
--- /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 <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.
+#
+############################################################################
+
+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 100644
index 000000000..bac9f3148
--- /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. Think 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/modbus/Kconfig b/apps/modbus/Kconfig
new file mode 100644
index 000000000..da95abf6a
--- /dev/null
+++ b/apps/modbus/Kconfig
@@ -0,0 +1,143 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+comment "FreeModbus"
+
+config MODBUS
+ bool "Modbus support via FreeModBus"
+ default n
+
+config MB_ASCII_ENABLED
+ bool "Modbus ASCII support"
+ depends on MODBUS
+ default y
+
+config MB_RTU_ENABLED
+ bool "Modbus RTU support"
+ depends on MODBUS
+ default y
+
+config MB_TCP_ENABLED
+ bool "Modbus TCP support"
+ depends on MODBUS
+ default y
+
+config MB_ASCII_TIMEOUT_SEC
+ int "Character timeout"
+ depends on MB_ASCII_ENABLED
+ default 1
+ ---help---
+ Character timeout value for Modbus ASCII
+
+ The character timeout value is not fixed for Modbus ASCII and is therefore
+ a configuration option. It should be set to the maximum expected delay
+ time of the network.
+
+config MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS
+ int "Timeout to wait before sending"
+ depends on MB_ASCII_ENABLED
+ default 0
+ ---help---
+ Timeout to wait in ASCII prior to enabling transmitter
+
+ If defined the function calls vMBPortSerialDelay with the argument
+ MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS to allow for a delay before
+ the serial transmitter is enabled. This is required because some
+ targets are so fast that there is no time between receiving and
+ transmitting the frame. If the master is to slow with enabling its
+ receiver then he will not receive the response correctly.
+
+config MB_FUNC_HANDLERS_MAX
+ int "Maximum number of Modbus functions"
+ depends on MODBUS
+ default 16
+ ---help---
+ Maximum number of Modbus functions codes the protocol stack should support.
+
+ The maximum number of supported Modbus functions must be greater than
+ the sum of all enabled functions in this file and custom function
+ handlers. If set to small adding more functions will fail.
+
+config MB_FUNC_OTHER_REP_SLAVEID_BUF
+ int "Size of Slave ID report buffer"
+ depends on MB_FUNC_OTHER_REP_SLAVEID_ENABLED
+ default 32
+ ---help---
+ Number of bytes which should be allocated for the Report Slave ID command.
+
+ This number limits the maximum size of the additional segment in the
+ report slave id function. See eMBSetSlaveID() for more information on
+ how to set this value. It is only used if MB_FUNC_OTHER_REP_SLAVEID_ENABLED
+ is set to 1.
+
+config MB_FUNC_OTHER_REP_SLAVEID_ENABLED
+ bool "Report Slave ID function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Report Slave ID function should be enabled.
+
+config MB_FUNC_READ_INPUT_ENABLED
+ bool "Read Input Registers function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Read Input Registers function should be enabled.
+
+config MB_FUNC_READ_HOLDING_ENABLED
+ bool "Read Holding Registers function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Read Holding Registers function should be enabled.
+
+config MB_FUNC_WRITE_HOLDING_ENABLED
+ bool "Write Single Register function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Write Single Register function should be enabled.
+
+config MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
+ bool "Write Multiple registers function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Write Multiple registers function should be enabled.
+
+config MB_FUNC_READ_COILS_ENABLED
+ bool "Read Coils function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Read Coils function should be enabled.
+
+config MB_FUNC_WRITE_COIL_ENABLED
+ bool "Write Coils function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Write Coils function should be enabled.
+
+config MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED
+ bool "Write Multiple Coils function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Write Multiple Coils function should be enabled.
+
+config MB_FUNC_READ_DISCRETE_INPUTS_ENABLED
+ bool "Read Discrete Inputs function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Read Discrete Inputs function should be enabled.
+
+config MB_FUNC_READWRITE_HOLDING_ENABLED
+ bool "Read/Write Multiple Registers function"
+ depends on MODBUS
+ default y
+ ---help---
+ If the Read/Write Multiple Registers function should be enabled.
diff --git a/apps/modbus/Make.defs b/apps/modbus/Make.defs
new file mode 100644
index 000000000..11a55aa31
--- /dev/null
+++ b/apps/modbus/Make.defs
@@ -0,0 +1,40 @@
+############################################################################
+# apps/modbus/Make.defs
+# Adds selected applications to apps/ build
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_MODBUS),y)
+CONFIGURED_APPS += modbus
+endif
+
diff --git a/apps/modbus/Makefile b/apps/modbus/Makefile
new file mode 100644
index 000000000..3cee14017
--- /dev/null
+++ b/apps/modbus/Makefile
@@ -0,0 +1,116 @@
+############################################################################
+# apps/modbus/Makefile
+#
+# Copyright (C) 2012 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
+
+# FreeModBus Library
+
+ASRCS =
+CSRCS =
+
+ifeq ($(CONFIG_MODBUS),y)
+
+CSRCS += mb.c
+DEPPATH = --dep-path .
+VPATH = .
+
+ifeq ($(WINTOOL),y)
+INCDIROPT = -w
+endif
+
+include ascii/Make.defs
+include functions/Make.defs
+include nuttx/Make.defs
+include rtu/Make.defs
+include tcp/Make.defs
+
+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
+
+# Build targets
+
+all: .built
+.PHONY: context .depend depend clean distclean
+
+ifeq ($(CONFIG_MODBUS),y)
+
+$(AOBJS): %$(OBJEXT): %.S
+ $(call ASSEMBLE, $<, $@)
+
+$(COBJS): %$(OBJEXT): %.c
+ $(call COMPILE, $<, $@)
+endif
+
+.built: $(OBJS)
+ifeq ($(CONFIG_MODBUS),y)
+ @( for obj in $(OBJS) ; do \
+ $(call ARCHIVE, $(BIN), $${obj}); \
+ done ; )
+ @touch .built
+endif
+
+context:
+
+.depend: Makefile $(SRCS)
+ifeq ($(CONFIG_MODBUS),y)
+ @$(MKDEP) $(DEPPATH) \
+ $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
+ @touch $@
+endif
+
+depend: .depend
+
+clean:
+ @rm -f *.o *~ .*.swp .built
+ $(call CLEAN)
+
+distclean: clean
+ @rm -f Make.dep .depend
+
+-include Make.dep
+
diff --git a/apps/modbus/README.txt b/apps/modbus/README.txt
new file mode 100644
index 000000000..c7a8ef245
--- /dev/null
+++ b/apps/modbus/README.txt
@@ -0,0 +1,117 @@
+apps/modbus README
+==================
+
+This directory contains a port of last open source version of FreeModBus
+(BSD license). The code in this directory is a subset of FreeModBus version
+1.5.0 (June 6, 2010) that can be downloaded in its entirety from http://developer.berlios.de/project/showfiles.php?group_id=6120.
+
+Directory Structure/Relation to freemodbus-v1.5.0
+-------------------------------------------------
+
+The original FreeModBus download consists of several directories. This
+subset takes only the contents of one directory, modbus/, that implements
+the core modbus logic and integrates that directory into the NuttX build
+system. The mapping between freemodbus-v1.5.0 and the nuttx directories
+is shown below:
+
+ --------------------------- ----------------------------------------------
+ freemodbus-v1.5.0 Nuttx
+ --------------------------- ----------------------------------------------
+ All top level .txt files Not included
+ demo/ Not included. This directory contains demo
+ and porting code for a variety of platforms.
+ The NuttX demo was ported from the the LINUX
+ demo in this director and can be found at
+ apps/examples/modbus.
+ doc/ Note included. This directory contains Doxygen
+ support files.
+ modbus/ Included in its entirety in various locations:
+ ascii apps/modbus/ascii
+ functions apps/modbus/functions
+ include apps/include/modbus
+ mb.c apps/modbus/mb.c
+ rtu apps/modbus/rtu
+ tcp apps/modbus/tcp
+ tools/ Note included. This directory contain Doxygen
+ tools.
+ --------------------------- ----------------------------------------------
+
+So this directory is equivalent to the freemodbus-v1.5.0/modbus
+directory except that (1) it may include modifications for the integration
+with NuttX and (2) the modbus/include directory was moved to apps/modbus.
+
+The original, unmodified freemodbus-v1.5.0 was checked in as SVN revision
+4960.
+
+The other directory here, nuttx/, implements the NuttX modbus interface.
+It derives from the freemodbus-v1.5.0/demo/LINUX/port directory.
+
+Configuration Options
+=====================
+
+In the original freemodbus-v1.5.0 release, the FreeModBus configuration
+was controlled by the header file mbconfig.h. This header file was
+eliminated (post revision 4960) and the FreeModBus configuration
+was integrated into the NuttX configuration system.
+
+The NuttX-named configuration options that are available include:
+
+ CONFIG_MODBUS - General ModBus support
+ CONFIG_MB_ASCII_ENABLED - Modbus ASCII support
+ CONFIG_MB_RTU_ENABLED - Modbus RTU support
+ CONFIG_MB_TCP_ENABLED - Modbus TCP support
+ CONFIG_MB_ASCII_TIMEOUT_SEC - Character timeout value for Modbus ASCII. The
+ character timeout value is not fixed for Modbus ASCII and is therefore
+ a configuration option. It should be set to the maximum expected delay
+ time of the network. Default 1
+ CONFIG_MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS - Timeout to wait in ASCII prior
+ to enabling transmitter. If defined the function calls
+ vMBPortSerialDelay with the argument CONFIG_MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS
+ to allow for a delay before the serial transmitter is enabled. This is
+ required because some targets are so fast that there is no time between
+ receiving and transmitting the frame. If the master is to slow with
+ enabling its receiver then he will not receive the response correctly.
+ CONFIG_MB_FUNC_HANDLERS_MAX - Maximum number of Modbus functions codes the
+ protocol stack should support. The maximum number of supported Modbus
+ functions must be greater than the sum of all enabled functions in this
+ file and custom function handlers. If set to small adding more functions
+ will fail.
+ CONFIG_MB_FUNC_OTHER_REP_SLAVEID_BUF - Number of bytes which should be
+ allocated for the Report Slave ID command. This number limits the
+ maximum size of the additional segment in the report slave id function.
+ See eMBSetSlaveID() for more information on how to set this value. It
+ is only used if CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED is set to 1.
+ CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED - If the Report Slave ID
+ function should be enabled.
+ CONFIG_MB_FUNC_READ_INPUT_ENABLED - If the Read Input Registers function
+ should be enabled.
+ CONFIG_MB_FUNC_READ_HOLDING_ENABLED - If the Read Holding Registers
+ function should be enabled.
+ CONFIG_MB_FUNC_WRITE_HOLDING_ENABLED - If the Write Single Register
+ function should be enabled.
+ CONFIG_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED - If the Write Multiple
+ registers function should be enabled.
+ CONFIG_MB_FUNC_READ_COILS_ENABLED - If the Read Coils function should
+ be enabled.
+ CONFIG_MB_FUNC_WRITE_COIL_ENABLED - If the Write Coils function should
+ be enabled.
+ CONFIG_MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED - If the Write Multiple Coils
+ function should be enabled.
+ CONFIG_MB_FUNC_READ_DISCRETE_INPUTS_ENABLED - If the Read Discrete Inputs
+ function should be enabled.
+ CONFIG_MB_FUNC_READWRITE_HOLDING_ENABLED - If the Read/Write Multiple
+ Registers function should be enabled.
+
+See also other serial settings, in particular:
+
+ CONFIG_SERIAL_TERMIOS - Serial driver supports termios.h interfaces (tcsetattr,
+ tcflush, etc.). If this is not defined, then the terminal settings (baud,
+ parity, etc.) are not configurable at runtime; serial streams will not be
+ flushed when closed.
+
+Note
+====
+
+The developer of FreeModBus, Christian Walter, is still developing Modbus
+libraries, although they are now commercial. See
+http://www.embedded-solutions.at/ for further information.
diff --git a/apps/modbus/ascii/Make.defs b/apps/modbus/ascii/Make.defs
new file mode 100644
index 000000000..3e9967283
--- /dev/null
+++ b/apps/modbus/ascii/Make.defs
@@ -0,0 +1,44 @@
+############################################################################
+# apps/modbus/functions/Make.defs
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_MB_ASCII_ENABLED),y)
+
+CSRCS += mbascii.c
+
+DEPPATH += --dep-path ascii
+VPATH += :ascii
+CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/ascii}
+
+endif
diff --git a/apps/modbus/ascii/mbascii.c b/apps/modbus/ascii/mbascii.c
new file mode 100644
index 000000000..4b8a56e01
--- /dev/null
+++ b/apps/modbus/ascii/mbascii.c
@@ -0,0 +1,487 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbascii.c,v 1.17 2010/06/06 13:47:07 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbframe.h>
+#include <apps/modbus/mbport.h>
+
+#include "mbascii.h"
+#include "mbcrc.h"
+
+#ifdef CONFIG_MB_ASCII_ENABLED
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_ASCII_DEFAULT_CR '\r' /*!< Default CR character for Modbus ASCII. */
+#define MB_ASCII_DEFAULT_LF '\n' /*!< Default LF character for Modbus ASCII. */
+#define MB_SER_PDU_SIZE_MIN 3 /*!< Minimum size of a Modbus ASCII frame. */
+#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus ASCII frame. */
+#define MB_SER_PDU_SIZE_LRC 1 /*!< Size of LRC field in PDU. */
+#define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
+#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
+
+/* ----------------------- Type definitions ---------------------------------*/
+typedef enum
+{
+ STATE_RX_IDLE, /*!< Receiver is in idle state. */
+ STATE_RX_RCV, /*!< Frame is beeing received. */
+ STATE_RX_WAIT_EOF /*!< Wait for End of Frame. */
+} eMBRcvState;
+
+typedef enum
+{
+ STATE_TX_IDLE, /*!< Transmitter is in idle state. */
+ STATE_TX_START, /*!< Starting transmission (':' sent). */
+ STATE_TX_DATA, /*!< Sending of data (Address, Data, LRC). */
+ STATE_TX_END, /*!< End of transmission. */
+ STATE_TX_NOTIFY /*!< Notify sender that the frame has been sent. */
+} eMBSndState;
+
+typedef enum
+{
+ BYTE_HIGH_NIBBLE, /*!< Character for high nibble of byte. */
+ BYTE_LOW_NIBBLE /*!< Character for low nibble of byte. */
+} eMBBytePos;
+
+/* ----------------------- Static functions ---------------------------------*/
+static uint8_t prvucMBint8_t2BIN( uint8_t ucCharacter );
+
+static uint8_t prvucMBBIN2int8_t( uint8_t ucByte );
+
+static uint8_t prvucMBLRC( uint8_t * pucFrame, uint16_t usLen );
+
+/* ----------------------- Static variables ---------------------------------*/
+static volatile eMBSndState eSndState;
+static volatile eMBRcvState eRcvState;
+
+/* We reuse the Modbus RTU buffer because only one buffer is needed and the
+ * RTU buffer is bigger. */
+extern volatile uint8_t ucRTUBuf[];
+static volatile uint8_t *ucASCIIBuf = ucRTUBuf;
+
+static volatile uint16_t usRcvBufferPos;
+static volatile eMBBytePos eBytePos;
+
+static volatile uint8_t *pucSndBufferCur;
+static volatile uint16_t usSndBufferCount;
+
+static volatile uint8_t ucLRC;
+static volatile uint8_t ucMBLFCharacter;
+
+/* ----------------------- Start implementation -----------------------------*/
+eMBErrorCode
+eMBASCIIInit( uint8_t ucSlaveAddress, uint8_t ucPort, speed_t ulBaudRate, eMBParity eParity )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+ ( void )ucSlaveAddress;
+
+ ENTER_CRITICAL_SECTION( );
+ ucMBLFCharacter = MB_ASCII_DEFAULT_LF;
+
+ if( xMBPortSerialInit( ucPort, ulBaudRate, 7, eParity ) != true )
+ {
+ eStatus = MB_EPORTERR;
+ }
+ else if( xMBPortTimersInit( CONFIG_MB_ASCII_TIMEOUT_SEC * 20000UL ) != true )
+ {
+ eStatus = MB_EPORTERR;
+ }
+
+ EXIT_CRITICAL_SECTION( );
+
+ return eStatus;
+}
+
+void
+eMBASCIIStart( void )
+{
+ ENTER_CRITICAL_SECTION( );
+ vMBPortSerialEnable( true, false );
+ eRcvState = STATE_RX_IDLE;
+ EXIT_CRITICAL_SECTION( );
+
+ /* No special startup required for ASCII. */
+ ( void )xMBPortEventPost( EV_READY );
+}
+
+void
+eMBASCIIStop( void )
+{
+ ENTER_CRITICAL_SECTION( );
+ vMBPortSerialEnable( false, false );
+ vMBPortTimersDisable( );
+ EXIT_CRITICAL_SECTION( );
+}
+
+eMBErrorCode
+eMBASCIIReceive( uint8_t * pucRcvAddress, uint8_t ** pucFrame, uint16_t * pusLength )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+
+ ENTER_CRITICAL_SECTION( );
+ ASSERT( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
+
+ /* Length and CRC check */
+ if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
+ && ( prvucMBLRC( ( uint8_t * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) )
+ {
+ /* Save the address field. All frames are passed to the upper layed
+ * and the decision if a frame is used is done there.
+ */
+ *pucRcvAddress = ucASCIIBuf[MB_SER_PDU_ADDR_OFF];
+
+ /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
+ * size of address field and CRC checksum.
+ */
+ *pusLength = ( uint16_t )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC );
+
+ /* Return the start of the Modbus PDU to the caller. */
+ *pucFrame = ( uint8_t * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
+ }
+ else
+ {
+ eStatus = MB_EIO;
+ }
+ EXIT_CRITICAL_SECTION( );
+ return eStatus;
+}
+
+eMBErrorCode
+eMBASCIISend( uint8_t ucSlaveAddress, const uint8_t * pucFrame, uint16_t usLength )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+ uint8_t usLRC;
+
+ ENTER_CRITICAL_SECTION( );
+ /* Check if the receiver is still in idle state. If not we where too
+ * slow with processing the received frame and the master sent another
+ * frame on the network. We have to abort sending the frame.
+ */
+ if( eRcvState == STATE_RX_IDLE )
+ {
+ /* First byte before the Modbus-PDU is the slave address. */
+ pucSndBufferCur = ( uint8_t * ) pucFrame - 1;
+ usSndBufferCount = 1;
+
+ /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
+ pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
+ usSndBufferCount += usLength;
+
+ /* Calculate LRC checksum for Modbus-Serial-Line-PDU. */
+ usLRC = prvucMBLRC( ( uint8_t * ) pucSndBufferCur, usSndBufferCount );
+ ucASCIIBuf[usSndBufferCount++] = usLRC;
+
+ /* Activate the transmitter. */
+ eSndState = STATE_TX_START;
+ vMBPortSerialEnable( false, true );
+ }
+ else
+ {
+ eStatus = MB_EIO;
+ }
+ EXIT_CRITICAL_SECTION( );
+ return eStatus;
+}
+
+bool
+xMBASCIIReceiveFSM( void )
+{
+ bool xNeedPoll = false;
+ uint8_t ucByte;
+ uint8_t ucResult;
+
+ ASSERT( eSndState == STATE_TX_IDLE );
+
+ ( void )xMBPortSerialGetByte( ( int8_t * ) & ucByte );
+ switch ( eRcvState )
+ {
+ /* A new character is received. If the character is a ':' the input
+ * buffer is cleared. A CR-character signals the end of the data
+ * block. Other characters are part of the data block and their
+ * ASCII value is converted back to a binary representation.
+ */
+ case STATE_RX_RCV:
+ /* Enable timer for character timeout. */
+ vMBPortTimersEnable( );
+ if( ucByte == ':' )
+ {
+ /* Empty receive buffer. */
+ eBytePos = BYTE_HIGH_NIBBLE;
+ usRcvBufferPos = 0;
+ }
+ else if( ucByte == MB_ASCII_DEFAULT_CR )
+ {
+ eRcvState = STATE_RX_WAIT_EOF;
+ }
+ else
+ {
+ ucResult = prvucMBint8_t2BIN( ucByte );
+ switch ( eBytePos )
+ {
+ /* High nibble of the byte comes first. We check for
+ * a buffer overflow here. */
+ case BYTE_HIGH_NIBBLE:
+ if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
+ {
+ ucASCIIBuf[usRcvBufferPos] = ( uint8_t )( ucResult << 4 );
+ eBytePos = BYTE_LOW_NIBBLE;
+ break;
+ }
+ else
+ {
+ /* not handled in Modbus specification but seems
+ * a resonable implementation. */
+ eRcvState = STATE_RX_IDLE;
+ /* Disable previously activated timer because of error state. */
+ vMBPortTimersDisable( );
+ }
+ break;
+
+ case BYTE_LOW_NIBBLE:
+ ucASCIIBuf[usRcvBufferPos] |= ucResult;
+ usRcvBufferPos++;
+ eBytePos = BYTE_HIGH_NIBBLE;
+ break;
+ }
+ }
+ break;
+
+ case STATE_RX_WAIT_EOF:
+ if( ucByte == ucMBLFCharacter )
+ {
+ /* Disable character timeout timer because all characters are
+ * received. */
+ vMBPortTimersDisable( );
+ /* Receiver is again in idle state. */
+ eRcvState = STATE_RX_IDLE;
+
+ /* Notify the caller of eMBASCIIReceive that a new frame
+ * was received. */
+ xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
+ }
+ else if( ucByte == ':' )
+ {
+ /* Empty receive buffer and back to receive state. */
+ eBytePos = BYTE_HIGH_NIBBLE;
+ usRcvBufferPos = 0;
+ eRcvState = STATE_RX_RCV;
+
+ /* Enable timer for character timeout. */
+ vMBPortTimersEnable( );
+ }
+ else
+ {
+ /* Frame is not okay. Delete entire frame. */
+ eRcvState = STATE_RX_IDLE;
+ }
+ break;
+
+ case STATE_RX_IDLE:
+ if( ucByte == ':' )
+ {
+ /* Enable timer for character timeout. */
+ vMBPortTimersEnable( );
+ /* Reset the input buffers to store the frame. */
+ usRcvBufferPos = 0;;
+ eBytePos = BYTE_HIGH_NIBBLE;
+ eRcvState = STATE_RX_RCV;
+ }
+ break;
+ }
+
+ return xNeedPoll;
+}
+
+bool
+xMBASCIITransmitFSM( void )
+{
+ bool xNeedPoll = false;
+ uint8_t ucByte;
+
+ ASSERT( eRcvState == STATE_RX_IDLE );
+ switch ( eSndState )
+ {
+ /* Start of transmission. The start of a frame is defined by sending
+ * the character ':'. */
+ case STATE_TX_START:
+ ucByte = ':';
+ xMBPortSerialPutByte( ( int8_t )ucByte );
+ eSndState = STATE_TX_DATA;
+ eBytePos = BYTE_HIGH_NIBBLE;
+ break;
+
+ /* Send the data block. Each data byte is encoded as a character hex
+ * stream with the high nibble sent first and the low nibble sent
+ * last. If all data bytes are exhausted we send a '\r' character
+ * to end the transmission. */
+ case STATE_TX_DATA:
+ if( usSndBufferCount > 0 )
+ {
+ switch ( eBytePos )
+ {
+ case BYTE_HIGH_NIBBLE:
+ ucByte = prvucMBBIN2int8_t( ( uint8_t )( *pucSndBufferCur >> 4 ) );
+ xMBPortSerialPutByte( ( int8_t ) ucByte );
+ eBytePos = BYTE_LOW_NIBBLE;
+ break;
+
+ case BYTE_LOW_NIBBLE:
+ ucByte = prvucMBBIN2int8_t( ( uint8_t )( *pucSndBufferCur & 0x0F ) );
+ xMBPortSerialPutByte( ( int8_t )ucByte );
+ pucSndBufferCur++;
+ eBytePos = BYTE_HIGH_NIBBLE;
+ usSndBufferCount--;
+ break;
+ }
+ }
+ else
+ {
+ xMBPortSerialPutByte( MB_ASCII_DEFAULT_CR );
+ eSndState = STATE_TX_END;
+ }
+ break;
+
+ /* Finish the frame by sending a LF character. */
+ case STATE_TX_END:
+ xMBPortSerialPutByte( ( int8_t )ucMBLFCharacter );
+ /* We need another state to make sure that the CR character has
+ * been sent. */
+ eSndState = STATE_TX_NOTIFY;
+ break;
+
+ /* Notify the task which called eMBASCIISend that the frame has
+ * been sent. */
+ case STATE_TX_NOTIFY:
+ eSndState = STATE_TX_IDLE;
+ xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
+
+ /* Disable transmitter. This prevents another transmit buffer
+ * empty interrupt. */
+ vMBPortSerialEnable( true, false );
+ eSndState = STATE_TX_IDLE;
+ break;
+
+ /* We should not get a transmitter event if the transmitter is in
+ * idle state. */
+ case STATE_TX_IDLE:
+ /* enable receiver/disable transmitter. */
+ vMBPortSerialEnable( true, false );
+ break;
+ }
+
+ return xNeedPoll;
+}
+
+bool
+xMBASCIITimerT1SExpired( void )
+{
+ switch ( eRcvState )
+ {
+ /* If we have a timeout we go back to the idle state and wait for
+ * the next frame.
+ */
+ case STATE_RX_RCV:
+ case STATE_RX_WAIT_EOF:
+ eRcvState = STATE_RX_IDLE;
+ break;
+
+ default:
+ ASSERT( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF ) );
+ break;
+ }
+ vMBPortTimersDisable( );
+
+ /* no context switch required. */
+ return false;
+}
+
+
+static uint8_t
+prvucMBint8_t2BIN( uint8_t ucCharacter )
+{
+ if( ( ucCharacter >= '0' ) && ( ucCharacter <= '9' ) )
+ {
+ return ( uint8_t )( ucCharacter - '0' );
+ }
+ else if( ( ucCharacter >= 'A' ) && ( ucCharacter <= 'F' ) )
+ {
+ return ( uint8_t )( ucCharacter - 'A' + 0x0A );
+ }
+ else
+ {
+ return 0xFF;
+ }
+}
+
+static uint8_t
+prvucMBBIN2int8_t( uint8_t ucByte )
+{
+ if( ucByte <= 0x09 )
+ {
+ return ( uint8_t )( '0' + ucByte );
+ }
+ else if( ( ucByte >= 0x0A ) && ( ucByte <= 0x0F ) )
+ {
+ return ( uint8_t )( ucByte - 0x0A + 'A' );
+ }
+ else
+ {
+ /* Programming error. */
+ ASSERT( 0 );
+ }
+ return '0';
+}
+
+
+static uint8_t
+prvucMBLRC( uint8_t * pucFrame, uint16_t usLen )
+{
+ uint8_t ucLocalLRC = 0; /* LRC char initialized */
+
+ while( usLen-- )
+ {
+ ucLocalLRC += *pucFrame++; /* Add buffer byte without carry */
+ }
+
+ /* Return twos complement */
+ ucLocalLRC = ( uint8_t ) ( -( ( int8_t ) ucLocalLRC ) );
+ return ucLocalLRC;
+}
+
+#endif
diff --git a/apps/modbus/ascii/mbascii.h b/apps/modbus/ascii/mbascii.h
new file mode 100644
index 000000000..96001404a
--- /dev/null
+++ b/apps/modbus/ascii/mbascii.h
@@ -0,0 +1,56 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbascii.h,v 1.8 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_ASCII_H
+#define _MB_ASCII_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+
+#ifdef CONFIG_MB_ASCII_ENABLED
+eMBErrorCode eMBASCIIInit( uint8_t slaveAddress, uint8_t ucPort,
+ speed_t ulBaudRate, eMBParity eParity );
+void eMBASCIIStart( void );
+void eMBASCIIStop( void );
+
+eMBErrorCode eMBASCIIReceive( uint8_t * pucRcvAddress, uint8_t ** pucFrame,
+ uint16_t * pusLength );
+eMBErrorCode eMBASCIISend( uint8_t slaveAddress, const uint8_t * pucFrame,
+ uint16_t usLength );
+bool xMBASCIIReceiveFSM( void );
+bool xMBASCIITransmitFSM( void );
+bool xMBASCIITimerT1SExpired( void );
+#endif
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/modbus/functions/Make.defs b/apps/modbus/functions/Make.defs
new file mode 100644
index 000000000..48f60d506
--- /dev/null
+++ b/apps/modbus/functions/Make.defs
@@ -0,0 +1,41 @@
+############################################################################
+# apps/modbus/nuttx/Make.defs
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+CSRCS += mbfunccoils.c mbfuncdiag.c mbfuncdisc.c mbfuncholding.c
+CSRCS += mbfuncinput.c mbfuncother.c mbutils.c
+
+DEPPATH += --dep-path functions
+VPATH += :functions
+CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/functions}
diff --git a/apps/modbus/functions/mbfunccoils.c b/apps/modbus/functions/mbfunccoils.c
new file mode 100644
index 000000000..d5f23c855
--- /dev/null
+++ b/apps/modbus/functions/mbfunccoils.c
@@ -0,0 +1,270 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbfunccoils.c,v 1.8 2007/02/18 23:47:16 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbframe.h>
+#include <apps/modbus/mbproto.h>
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READ_SIZE ( 4 )
+#define MB_PDU_FUNC_READ_COILCNT_MAX ( 0x07D0 )
+
+#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
+
+#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
+#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
+#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN ( 5 )
+#define MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ( 0x07B0 )
+
+/* ----------------------- Static functions ---------------------------------*/
+eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
+
+/* ----------------------- Start implementation -----------------------------*/
+
+#ifdef CONFIG_MB_FUNC_READ_COILS_ENABLED
+
+eMBException
+eMBFuncReadCoils( uint8_t * pucFrame, uint16_t * usLen )
+{
+ uint16_t usRegAddress;
+ uint16_t usCoilCount;
+ uint8_t ucNBytes;
+ uint8_t *pucFrameCur;
+
+ eMBException eStatus = MB_EX_NONE;
+ eMBErrorCode eRegStatus;
+
+ if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
+ {
+ usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
+ usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
+ usRegAddress++;
+
+ usCoilCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8 );
+ usCoilCount |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF + 1] );
+
+ /* Check if the number of registers to read is valid. If not
+ * return Modbus illegal data value exception.
+ */
+ if( ( usCoilCount >= 1 ) &&
+ ( usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX ) )
+ {
+ /* Set the current PDU data pointer to the beginning. */
+ pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+ *usLen = MB_PDU_FUNC_OFF;
+
+ /* First byte contains the function code. */
+ *pucFrameCur++ = MB_FUNC_READ_COILS;
+ *usLen += 1;
+
+ /* Test if the quantity of coils is a multiple of 8. If not last
+ * byte is only partially field with unused coils set to zero. */
+ if( ( usCoilCount & 0x0007 ) != 0 )
+ {
+ ucNBytes = ( uint8_t )( usCoilCount / 8 + 1 );
+ }
+ else
+ {
+ ucNBytes = ( uint8_t )( usCoilCount / 8 );
+ }
+ *pucFrameCur++ = ucNBytes;
+ *usLen += 1;
+
+ eRegStatus =
+ eMBRegCoilsCB( pucFrameCur, usRegAddress, usCoilCount,
+ MB_REG_READ );
+
+ /* If an error occured convert it into a Modbus exception. */
+ if( eRegStatus != MB_ENOERR )
+ {
+ eStatus = prveMBError2Exception( eRegStatus );
+ }
+ else
+ {
+ /* The response contains the function code, the starting address
+ * and the quantity of registers. We reuse the old values in the
+ * buffer because they are still valid. */
+ *usLen += ucNBytes;;
+ }
+ }
+ else
+ {
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ }
+ else
+ {
+ /* Can't be a valid read coil register request because the length
+ * is incorrect. */
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ return eStatus;
+}
+
+#ifdef CONFIG_MB_FUNC_WRITE_COIL_ENABLED
+eMBException
+eMBFuncWriteCoil( uint8_t * pucFrame, uint16_t * usLen )
+{
+ uint16_t usRegAddress;
+ uint8_t ucBuf[2];
+
+ eMBException eStatus = MB_EX_NONE;
+ eMBErrorCode eRegStatus;
+
+ if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
+ {
+ usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
+ usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
+ usRegAddress++;
+
+ if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) &&
+ ( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF ) ||
+ ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00 ) ) )
+ {
+ ucBuf[1] = 0;
+ if( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF )
+ {
+ ucBuf[0] = 1;
+ }
+ else
+ {
+ ucBuf[0] = 0;
+ }
+ eRegStatus =
+ eMBRegCoilsCB( &ucBuf[0], usRegAddress, 1, MB_REG_WRITE );
+
+ /* If an error occured convert it into a Modbus exception. */
+ if( eRegStatus != MB_ENOERR )
+ {
+ eStatus = prveMBError2Exception( eRegStatus );
+ }
+ }
+ else
+ {
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ }
+ else
+ {
+ /* Can't be a valid write coil register request because the length
+ * is incorrect. */
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ return eStatus;
+}
+
+#endif
+
+#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED
+eMBException
+eMBFuncWriteMultipleCoils( uint8_t * pucFrame, uint16_t * usLen )
+{
+ uint16_t usRegAddress;
+ uint16_t usCoilCnt;
+ uint8_t ucByteCount;
+ uint8_t ucByteCountVerify;
+
+ eMBException eStatus = MB_EX_NONE;
+ eMBErrorCode eRegStatus;
+
+ if( *usLen > ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
+ {
+ usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
+ usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
+ usRegAddress++;
+
+ usCoilCnt = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8 );
+ usCoilCnt |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1] );
+
+ ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
+
+ /* Compute the number of expected bytes in the request. */
+ if( ( usCoilCnt & 0x0007 ) != 0 )
+ {
+ ucByteCountVerify = ( uint8_t )( usCoilCnt / 8 + 1 );
+ }
+ else
+ {
+ ucByteCountVerify = ( uint8_t )( usCoilCnt / 8 );
+ }
+
+ if( ( usCoilCnt >= 1 ) &&
+ ( usCoilCnt <= MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ) &&
+ ( ucByteCountVerify == ucByteCount ) )
+ {
+ eRegStatus =
+ eMBRegCoilsCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
+ usRegAddress, usCoilCnt, MB_REG_WRITE );
+
+ /* If an error occured convert it into a Modbus exception. */
+ if( eRegStatus != MB_ENOERR )
+ {
+ eStatus = prveMBError2Exception( eRegStatus );
+ }
+ else
+ {
+ /* The response contains the function code, the starting address
+ * and the quantity of registers. We reuse the old values in the
+ * buffer because they are still valid. */
+ *usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
+ }
+ }
+ else
+ {
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ }
+ else
+ {
+ /* Can't be a valid write coil register request because the length
+ * is incorrect. */
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ return eStatus;
+}
+
+#endif
+
+#endif
diff --git a/apps/modbus/functions/mbfuncdiag.c b/apps/modbus/functions/mbfuncdiag.c
new file mode 100644
index 000000000..d75ffc0f7
--- /dev/null
+++ b/apps/modbus/functions/mbfuncdiag.c
@@ -0,0 +1,29 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbfuncdiag.c,v 1.3 2006/12/07 22:10:34 wolti Exp $
+ */
diff --git a/apps/modbus/functions/mbfuncdisc.c b/apps/modbus/functions/mbfuncdisc.c
new file mode 100644
index 000000000..6f291bf2f
--- /dev/null
+++ b/apps/modbus/functions/mbfuncdisc.c
@@ -0,0 +1,123 @@
+ /*
+ * FreeRTOS Modbus Libary: A Modbus serial implementation for FreeRTOS
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbframe.h>
+#include <apps/modbus/mbproto.h>
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_READ_DISCCNT_OFF ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READ_SIZE ( 4 )
+#define MB_PDU_FUNC_READ_DISCCNT_MAX ( 0x07D0 )
+
+/* ----------------------- Static functions ---------------------------------*/
+eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
+
+/* ----------------------- Start implementation -----------------------------*/
+
+#ifdef CONFIG_MB_FUNC_READ_COILS_ENABLED
+
+eMBException
+eMBFuncReadDiscreteInputs( uint8_t * pucFrame, uint16_t * usLen )
+{
+ uint16_t usRegAddress;
+ uint16_t usDiscreteCnt;
+ uint8_t ucNBytes;
+ uint8_t *pucFrameCur;
+
+ eMBException eStatus = MB_EX_NONE;
+ eMBErrorCode eRegStatus;
+
+ if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
+ {
+ usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
+ usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
+ usRegAddress++;
+
+ usDiscreteCnt = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF] << 8 );
+ usDiscreteCnt |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF + 1] );
+
+ /* Check if the number of registers to read is valid. If not
+ * return Modbus illegal data value exception.
+ */
+ if( ( usDiscreteCnt >= 1 ) &&
+ ( usDiscreteCnt < MB_PDU_FUNC_READ_DISCCNT_MAX ) )
+ {
+ /* Set the current PDU data pointer to the beginning. */
+ pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+ *usLen = MB_PDU_FUNC_OFF;
+
+ /* First byte contains the function code. */
+ *pucFrameCur++ = MB_FUNC_READ_DISCRETE_INPUTS;
+ *usLen += 1;
+
+ /* Test if the quantity of coils is a multiple of 8. If not last
+ * byte is only partially field with unused coils set to zero. */
+ if( ( usDiscreteCnt & 0x0007 ) != 0 )
+ {
+ ucNBytes = ( uint8_t ) ( usDiscreteCnt / 8 + 1 );
+ }
+ else
+ {
+ ucNBytes = ( uint8_t ) ( usDiscreteCnt / 8 );
+ }
+ *pucFrameCur++ = ucNBytes;
+ *usLen += 1;
+
+ eRegStatus =
+ eMBRegDiscreteCB( pucFrameCur, usRegAddress, usDiscreteCnt );
+
+ /* If an error occured convert it into a Modbus exception. */
+ if( eRegStatus != MB_ENOERR )
+ {
+ eStatus = prveMBError2Exception( eRegStatus );
+ }
+ else
+ {
+ /* The response contains the function code, the starting address
+ * and the quantity of registers. We reuse the old values in the
+ * buffer because they are still valid. */
+ *usLen += ucNBytes;;
+ }
+ }
+ else
+ {
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ }
+ else
+ {
+ /* Can't be a valid read coil register request because the length
+ * is incorrect. */
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ return eStatus;
+}
+
+#endif
diff --git a/apps/modbus/functions/mbfuncholding.c b/apps/modbus/functions/mbfuncholding.c
new file mode 100644
index 000000000..885ce34ca
--- /dev/null
+++ b/apps/modbus/functions/mbfuncholding.c
@@ -0,0 +1,308 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbfuncholding.c,v 1.12 2007/02/18 23:48:22 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbframe.h>
+#include <apps/modbus/mbproto.h>
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
+#define MB_PDU_FUNC_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READ_SIZE ( 4 )
+#define MB_PDU_FUNC_READ_REGCNT_MAX ( 0x007D )
+
+#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
+#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
+
+#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
+#define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
+#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
+#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN ( 5 )
+#define MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ( 0x0078 )
+
+#define MB_PDU_FUNC_READWRITE_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
+#define MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 4 )
+#define MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF ( MB_PDU_DATA_OFF + 6 )
+#define MB_PDU_FUNC_READWRITE_BYTECNT_OFF ( MB_PDU_DATA_OFF + 8 )
+#define MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF ( MB_PDU_DATA_OFF + 9 )
+#define MB_PDU_FUNC_READWRITE_SIZE_MIN ( 9 )
+
+/* ----------------------- Static functions ---------------------------------*/
+eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
+
+/* ----------------------- Start implementation -----------------------------*/
+
+#ifdef CONFIG_MB_FUNC_WRITE_HOLDING_ENABLED
+
+eMBException
+eMBFuncWriteHoldingRegister( uint8_t * pucFrame, uint16_t * usLen )
+{
+ uint16_t usRegAddress;
+ eMBException eStatus = MB_EX_NONE;
+ eMBErrorCode eRegStatus;
+
+ if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
+ {
+ usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
+ usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
+ usRegAddress++;
+
+ /* Make callback to update the value. */
+ eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
+ usRegAddress, 1, MB_REG_WRITE );
+
+ /* If an error occured convert it into a Modbus exception. */
+ if( eRegStatus != MB_ENOERR )
+ {
+ eStatus = prveMBError2Exception( eRegStatus );
+ }
+ }
+ else
+ {
+ /* Can't be a valid request because the length is incorrect. */
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ return eStatus;
+}
+#endif
+
+#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
+eMBException
+eMBFuncWriteMultipleHoldingRegister( uint8_t * pucFrame, uint16_t * usLen )
+{
+ uint16_t usRegAddress;
+ uint16_t usRegCount;
+ uint8_t ucRegByteCount;
+
+ eMBException eStatus = MB_EX_NONE;
+ eMBErrorCode eRegStatus;
+
+ if( *usLen >= ( MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MB_PDU_SIZE_MIN ) )
+ {
+ usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
+ usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
+ usRegAddress++;
+
+ usRegCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 );
+ usRegCount |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF + 1] );
+
+ ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
+
+ if( ( usRegCount >= 1 ) &&
+ ( usRegCount <= MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ) &&
+ ( ucRegByteCount == ( uint8_t ) ( 2 * usRegCount ) ) )
+ {
+ /* Make callback to update the register values. */
+ eRegStatus =
+ eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
+ usRegAddress, usRegCount, MB_REG_WRITE );
+
+ /* If an error occured convert it into a Modbus exception. */
+ if( eRegStatus != MB_ENOERR )
+ {
+ eStatus = prveMBError2Exception( eRegStatus );
+ }
+ else
+ {
+ /* The response contains the function code, the starting
+ * address and the quantity of registers. We reuse the
+ * old values in the buffer because they are still valid.
+ */
+ *usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
+ }
+ }
+ else
+ {
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ }
+ else
+ {
+ /* Can't be a valid request because the length is incorrect. */
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ return eStatus;
+}
+#endif
+
+#ifdef CONFIG_MB_FUNC_READ_HOLDING_ENABLED
+
+eMBException
+eMBFuncReadHoldingRegister( uint8_t * pucFrame, uint16_t * usLen )
+{
+ uint16_t usRegAddress;
+ uint16_t usRegCount;
+ uint8_t *pucFrameCur;
+
+ eMBException eStatus = MB_EX_NONE;
+ eMBErrorCode eRegStatus;
+
+ if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
+ {
+ usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
+ usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
+ usRegAddress++;
+
+ usRegCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
+ usRegCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
+
+ /* Check if the number of registers to read is valid. If not
+ * return Modbus illegal data value exception.
+ */
+ if( ( usRegCount >= 1 ) && ( usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX ) )
+ {
+ /* Set the current PDU data pointer to the beginning. */
+ pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+ *usLen = MB_PDU_FUNC_OFF;
+
+ /* First byte contains the function code. */
+ *pucFrameCur++ = MB_FUNC_READ_HOLDING_REGISTER;
+ *usLen += 1;
+
+ /* Second byte in the response contain the number of bytes. */
+ *pucFrameCur++ = ( uint8_t ) ( usRegCount * 2 );
+ *usLen += 1;
+
+ /* Make callback to fill the buffer. */
+ eRegStatus = eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ );
+ /* If an error occured convert it into a Modbus exception. */
+ if( eRegStatus != MB_ENOERR )
+ {
+ eStatus = prveMBError2Exception( eRegStatus );
+ }
+ else
+ {
+ *usLen += usRegCount * 2;
+ }
+ }
+ else
+ {
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ }
+ else
+ {
+ /* Can't be a valid request because the length is incorrect. */
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ return eStatus;
+}
+
+#endif
+
+#ifdef CONFIG_MB_FUNC_READWRITE_HOLDING_ENABLED
+
+eMBException
+eMBFuncReadWriteMultipleHoldingRegister( uint8_t * pucFrame, uint16_t * usLen )
+{
+ uint16_t usRegReadAddress;
+ uint16_t usRegReadCount;
+ uint16_t usRegWriteAddress;
+ uint16_t usRegWriteCount;
+ uint8_t ucRegWriteByteCount;
+ uint8_t *pucFrameCur;
+
+ eMBException eStatus = MB_EX_NONE;
+ eMBErrorCode eRegStatus;
+
+ if( *usLen >= ( MB_PDU_FUNC_READWRITE_SIZE_MIN + MB_PDU_SIZE_MIN ) )
+ {
+ usRegReadAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U );
+ usRegReadAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF + 1] );
+ usRegReadAddress++;
+
+ usRegReadCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U );
+ usRegReadCount |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF + 1] );
+
+ usRegWriteAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U );
+ usRegWriteAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF + 1] );
+ usRegWriteAddress++;
+
+ usRegWriteCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U );
+ usRegWriteCount |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF + 1] );
+
+ ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF];
+
+ if( ( usRegReadCount >= 1 ) && ( usRegReadCount <= 0x7D ) &&
+ ( usRegWriteCount >= 1 ) && ( usRegWriteCount <= 0x79 ) &&
+ ( ( 2 * usRegWriteCount ) == ucRegWriteByteCount ) )
+ {
+ /* Make callback to update the register values. */
+ eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF],
+ usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
+
+ if( eRegStatus == MB_ENOERR )
+ {
+ /* Set the current PDU data pointer to the beginning. */
+ pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+ *usLen = MB_PDU_FUNC_OFF;
+
+ /* First byte contains the function code. */
+ *pucFrameCur++ = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
+ *usLen += 1;
+
+ /* Second byte in the response contain the number of bytes. */
+ *pucFrameCur++ = ( uint8_t ) ( usRegReadCount * 2 );
+ *usLen += 1;
+
+ /* Make the read callback. */
+ eRegStatus =
+ eMBRegHoldingCB( pucFrameCur, usRegReadAddress, usRegReadCount, MB_REG_READ );
+ if( eRegStatus == MB_ENOERR )
+ {
+ *usLen += 2 * usRegReadCount;
+ }
+ }
+ if( eRegStatus != MB_ENOERR )
+ {
+ eStatus = prveMBError2Exception( eRegStatus );
+ }
+ }
+ else
+ {
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ }
+ return eStatus;
+}
+
+#endif
diff --git a/apps/modbus/functions/mbfuncinput.c b/apps/modbus/functions/mbfuncinput.c
new file mode 100644
index 000000000..3061340f6
--- /dev/null
+++ b/apps/modbus/functions/mbfuncinput.c
@@ -0,0 +1,122 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbfuncinput.c,v 1.10 2007/09/12 10:15:56 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbframe.h>
+#include <apps/modbus/mbproto.h>
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READ_SIZE ( 4 )
+#define MB_PDU_FUNC_READ_REGCNT_MAX ( 0x007D )
+
+#define MB_PDU_FUNC_READ_RSP_BYTECNT_OFF ( MB_PDU_DATA_OFF )
+
+/* ----------------------- Static functions ---------------------------------*/
+eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
+
+/* ----------------------- Start implementation -----------------------------*/
+
+#ifdef CONFIG_MB_FUNC_READ_INPUT_ENABLED
+eMBException
+eMBFuncReadInputRegister( uint8_t * pucFrame, uint16_t * usLen )
+{
+ uint16_t usRegAddress;
+ uint16_t usRegCount;
+ uint8_t *pucFrameCur;
+
+ eMBException eStatus = MB_EX_NONE;
+ eMBErrorCode eRegStatus;
+
+ if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
+ {
+ usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
+ usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
+ usRegAddress++;
+
+ usRegCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
+ usRegCount |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
+
+ /* Check if the number of registers to read is valid. If not
+ * return Modbus illegal data value exception.
+ */
+ if( ( usRegCount >= 1 )
+ && ( usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX ) )
+ {
+ /* Set the current PDU data pointer to the beginning. */
+ pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+ *usLen = MB_PDU_FUNC_OFF;
+
+ /* First byte contains the function code. */
+ *pucFrameCur++ = MB_FUNC_READ_INPUT_REGISTER;
+ *usLen += 1;
+
+ /* Second byte in the response contain the number of bytes. */
+ *pucFrameCur++ = ( uint8_t )( usRegCount * 2 );
+ *usLen += 1;
+
+ eRegStatus =
+ eMBRegInputCB( pucFrameCur, usRegAddress, usRegCount );
+
+ /* If an error occured convert it into a Modbus exception. */
+ if( eRegStatus != MB_ENOERR )
+ {
+ eStatus = prveMBError2Exception( eRegStatus );
+ }
+ else
+ {
+ *usLen += usRegCount * 2;
+ }
+ }
+ else
+ {
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ }
+ else
+ {
+ /* Can't be a valid read input register request because the length
+ * is incorrect. */
+ eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+ }
+ return eStatus;
+}
+
+#endif
diff --git a/apps/modbus/functions/mbfuncother.c b/apps/modbus/functions/mbfuncother.c
new file mode 100644
index 000000000..ea733e905
--- /dev/null
+++ b/apps/modbus/functions/mbfuncother.c
@@ -0,0 +1,88 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbfuncother.c,v 1.8 2006/12/07 22:10:34 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbframe.h>
+#include <apps/modbus/mbproto.h>
+
+#ifdef CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED
+
+/* ----------------------- Static variables ---------------------------------*/
+static uint8_t ucMBSlaveID[CONFIG_MB_FUNC_OTHER_REP_SLAVEID_BUF];
+static uint16_t usMBSlaveIDLen;
+
+/* ----------------------- Start implementation -----------------------------*/
+
+eMBErrorCode
+eMBSetSlaveID( uint8_t ucSlaveID, bool xIsRunning,
+ uint8_t const *pucAdditional, uint16_t usAdditionalLen )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+
+ /* the first byte and second byte in the buffer is reserved for
+ * the parameter ucSlaveID and the running flag. The rest of
+ * the buffer is available for additional data. */
+ if( usAdditionalLen + 2 < CONFIG_MB_FUNC_OTHER_REP_SLAVEID_BUF )
+ {
+ usMBSlaveIDLen = 0;
+ ucMBSlaveID[usMBSlaveIDLen++] = ucSlaveID;
+ ucMBSlaveID[usMBSlaveIDLen++] = ( uint8_t )( xIsRunning ? 0xFF : 0x00 );
+ if( usAdditionalLen > 0 )
+ {
+ memcpy( &ucMBSlaveID[usMBSlaveIDLen], pucAdditional,
+ ( size_t )usAdditionalLen );
+ usMBSlaveIDLen += usAdditionalLen;
+ }
+ }
+ else
+ {
+ eStatus = MB_ENORES;
+ }
+ return eStatus;
+}
+
+eMBException
+eMBFuncReportSlaveID( uint8_t * pucFrame, uint16_t * usLen )
+{
+ memcpy( &pucFrame[MB_PDU_DATA_OFF], &ucMBSlaveID[0], ( size_t )usMBSlaveIDLen );
+ *usLen = ( uint16_t )( MB_PDU_DATA_OFF + usMBSlaveIDLen );
+ return MB_EX_NONE;
+}
+
+#endif
diff --git a/apps/modbus/functions/mbutils.c b/apps/modbus/functions/mbutils.c
new file mode 100644
index 000000000..cbe02872b
--- /dev/null
+++ b/apps/modbus/functions/mbutils.c
@@ -0,0 +1,143 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbutils.c,v 1.6 2007/02/18 23:49:07 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbproto.h>
+
+/* ----------------------- Defines ------------------------------------------*/
+#define BITS_uint8_t 8U
+
+/* ----------------------- Start implementation -----------------------------*/
+void
+xMBUtilSetBits( uint8_t * ucByteBuf, uint16_t usBitOffset, uint8_t ucNBits,
+ uint8_t ucValue )
+{
+ uint16_t usWordBuf;
+ uint16_t usMask;
+ uint16_t usByteOffset;
+ uint16_t usNPreBits;
+ uint16_t usValue = ucValue;
+
+ ASSERT( ucNBits <= 8 );
+ ASSERT( ( size_t )BITS_uint8_t == sizeof( uint8_t ) * 8 );
+
+ /* Calculate byte offset for first byte containing the bit values starting
+ * at usBitOffset. */
+ usByteOffset = ( uint16_t )( ( usBitOffset ) / BITS_uint8_t );
+
+ /* How many bits precede our bits to set. */
+ usNPreBits = ( uint16_t )( usBitOffset - usByteOffset * BITS_uint8_t );
+
+ /* Move bit field into position over bits to set */
+ usValue <<= usNPreBits;
+
+ /* Prepare a mask for setting the new bits. */
+ usMask = ( uint16_t )( ( 1 << ( uint16_t ) ucNBits ) - 1 );
+ usMask <<= usBitOffset - usByteOffset * BITS_uint8_t;
+
+ /* copy bits into temporary storage. */
+ usWordBuf = ucByteBuf[usByteOffset];
+ usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_uint8_t;
+
+ /* Zero out bit field bits and then or value bits into them. */
+ usWordBuf = ( uint16_t )( ( usWordBuf & ( ~usMask ) ) | usValue );
+
+ /* move bits back into storage */
+ ucByteBuf[usByteOffset] = ( uint8_t )( usWordBuf & 0xFF );
+ ucByteBuf[usByteOffset + 1] = ( uint8_t )( usWordBuf >> BITS_uint8_t );
+}
+
+uint8_t
+xMBUtilGetBits( uint8_t * ucByteBuf, uint16_t usBitOffset, uint8_t ucNBits )
+{
+ uint16_t usWordBuf;
+ uint16_t usMask;
+ uint16_t usByteOffset;
+ uint16_t usNPreBits;
+
+ /* Calculate byte offset for first byte containing the bit values starting
+ * at usBitOffset. */
+ usByteOffset = ( uint16_t )( ( usBitOffset ) / BITS_uint8_t );
+
+ /* How many bits precede our bits to set. */
+ usNPreBits = ( uint16_t )( usBitOffset - usByteOffset * BITS_uint8_t );
+
+ /* Prepare a mask for setting the new bits. */
+ usMask = ( uint16_t )( ( 1 << ( uint16_t ) ucNBits ) - 1 );
+
+ /* copy bits into temporary storage. */
+ usWordBuf = ucByteBuf[usByteOffset];
+ usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_uint8_t;
+
+ /* throw away unneeded bits. */
+ usWordBuf >>= usNPreBits;
+
+ /* mask away bits above the requested bitfield. */
+ usWordBuf &= usMask;
+
+ return ( uint8_t ) usWordBuf;
+}
+
+eMBException
+prveMBError2Exception( eMBErrorCode eErrorCode )
+{
+ eMBException eStatus;
+
+ switch ( eErrorCode )
+ {
+ case MB_ENOERR:
+ eStatus = MB_EX_NONE;
+ break;
+
+ case MB_ENOREG:
+ eStatus = MB_EX_ILLEGAL_DATA_ADDRESS;
+ break;
+
+ case MB_ETIMEDOUT:
+ eStatus = MB_EX_SLAVE_BUSY;
+ break;
+
+ default:
+ eStatus = MB_EX_SLAVE_DEVICE_FAILURE;
+ break;
+ }
+
+ return eStatus;
+}
diff --git a/apps/modbus/mb.c b/apps/modbus/mb.c
new file mode 100644
index 000000000..209b1274c
--- /dev/null
+++ b/apps/modbus/mb.c
@@ -0,0 +1,415 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mb.c,v 1.28 2010/06/06 13:54:40 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbframe.h>
+#include <apps/modbus/mbproto.h>
+#include <apps/modbus/mbfunc.h>
+
+#include <apps/modbus/mbport.h>
+
+#ifdef CONFIG_MB_RTU_ENABLED
+#include "mbrtu.h"
+#endif
+
+#ifdef CONFIG_MB_ASCII_ENABLED
+#include "mbascii.h"
+#endif
+
+#ifdef CONFIG_MB_TCP_ENABLED
+#include "mbtcp.h"
+#endif
+
+#ifndef MB_PORT_HAS_CLOSE
+#define MB_PORT_HAS_CLOSE 0
+#endif
+
+/* ----------------------- Static variables ---------------------------------*/
+
+static uint8_t ucMBAddress;
+static eMBMode eMBCurrentMode;
+
+static enum
+{
+ STATE_ENABLED,
+ STATE_DISABLED,
+ STATE_NOT_INITIALIZED
+} eMBState = STATE_NOT_INITIALIZED;
+
+/* Functions pointer which are initialized in eMBInit( ). Depending on the
+ * mode (RTU or ASCII) the are set to the correct implementations.
+ */
+static peMBFrameSend peMBFrameSendCur;
+static pvMBFrameStart pvMBFrameStartCur;
+static pvMBFrameStop pvMBFrameStopCur;
+static peMBFrameReceive peMBFrameReceiveCur;
+static pvMBFrameClose pvMBFrameCloseCur;
+
+/* Callback functions required by the porting layer. They are called when
+ * an external event has happend which includes a timeout or the reception
+ * or transmission of a character.
+ */
+bool( *pxMBFrameCBByteReceived ) ( void );
+bool( *pxMBFrameCBTransmitterEmpty ) ( void );
+bool( *pxMBPortCBTimerExpired ) ( void );
+
+bool( *pxMBFrameCBReceiveFSMCur ) ( void );
+bool( *pxMBFrameCBTransmitFSMCur ) ( void );
+
+/* An array of Modbus functions handlers which associates Modbus function
+ * codes with implementing functions.
+ */
+static xMBFunctionHandler xFuncHandlers[CONFIG_MB_FUNC_HANDLERS_MAX] = {
+#ifdef CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED
+ {MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
+#endif
+#ifdef CONFIG_MB_FUNC_READ_INPUT_ENABLE
+ {MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister},
+#endif
+#ifdef CONFIG_MB_FUNC_READ_HOLDING_ENABLED
+ {MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister},
+#endif
+#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
+ {MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister},
+#endif
+#ifdef CONFIG_MB_FUNC_WRITE_HOLDING_ENABLED
+ {MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister},
+#endif
+#ifdef CONFIG_MB_FUNC_READWRITE_HOLDING_ENABLED
+ {MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister},
+#endif
+#ifdef CONFIG_MB_FUNC_READ_COILS_ENABLED
+ {MB_FUNC_READ_COILS, eMBFuncReadCoils},
+#endif
+#ifdef CONFIG_MB_FUNC_WRITE_COIL_ENABLED
+ {MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil},
+#endif
+#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED
+ {MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils},
+#endif
+#ifdef CONFIG_MB_FUNC_READ_DISCRETE_INPUTS_ENABLED
+ {MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs},
+#endif
+};
+
+/* ----------------------- Start implementation -----------------------------*/
+eMBErrorCode
+eMBInit( eMBMode eMode, uint8_t ucSlaveAddress, uint8_t ucPort, speed_t ulBaudRate, eMBParity eParity )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+
+ /* check preconditions */
+ if( ( ucSlaveAddress == MB_ADDRESS_BROADCAST ) ||
+ ( ucSlaveAddress < MB_ADDRESS_MIN ) || ( ucSlaveAddress > MB_ADDRESS_MAX ) )
+ {
+ eStatus = MB_EINVAL;
+ }
+ else
+ {
+ ucMBAddress = ucSlaveAddress;
+
+ switch ( eMode )
+ {
+#ifdef CONFIG_MB_RTU_ENABLED
+ case MB_RTU:
+ pvMBFrameStartCur = eMBRTUStart;
+ pvMBFrameStopCur = eMBRTUStop;
+ peMBFrameSendCur = eMBRTUSend;
+ peMBFrameReceiveCur = eMBRTUReceive;
+ pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
+ pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
+ pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;
+ pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;
+
+ eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
+ break;
+#endif
+#ifdef CONFIG_MB_ASCII_ENABLED
+ case MB_ASCII:
+ pvMBFrameStartCur = eMBASCIIStart;
+ pvMBFrameStopCur = eMBASCIIStop;
+ peMBFrameSendCur = eMBASCIISend;
+ peMBFrameReceiveCur = eMBASCIIReceive;
+ pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
+ pxMBFrameCBByteReceived = xMBASCIIReceiveFSM;
+ pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM;
+ pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired;
+
+ eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity );
+ break;
+#endif
+ default:
+ eStatus = MB_EINVAL;
+ }
+
+ if( eStatus == MB_ENOERR )
+ {
+ if( !xMBPortEventInit( ) )
+ {
+ /* port dependent event module initalization failed. */
+ eStatus = MB_EPORTERR;
+ }
+ else
+ {
+ eMBCurrentMode = eMode;
+ eMBState = STATE_DISABLED;
+ }
+ }
+ }
+ return eStatus;
+}
+
+#ifdef CONFIG_MB_TCP_ENABLED
+eMBErrorCode
+eMBTCPInit( uint16_t ucTCPPort )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+
+ if( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR )
+ {
+ eMBState = STATE_DISABLED;
+ }
+ else if( !xMBPortEventInit( ) )
+ {
+ /* Port dependent event module initalization failed. */
+ eStatus = MB_EPORTERR;
+ }
+ else
+ {
+ pvMBFrameStartCur = eMBTCPStart;
+ pvMBFrameStopCur = eMBTCPStop;
+ peMBFrameReceiveCur = eMBTCPReceive;
+ peMBFrameSendCur = eMBTCPSend;
+ pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL;
+ ucMBAddress = MB_TCP_PSEUDO_ADDRESS;
+ eMBCurrentMode = MB_TCP;
+ eMBState = STATE_DISABLED;
+ }
+ return eStatus;
+}
+#endif
+
+eMBErrorCode
+eMBRegisterCB( uint8_t ucFunctionCode, pxMBFunctionHandler pxHandler )
+{
+ int i;
+ eMBErrorCode eStatus;
+
+ if( ( 0 < ucFunctionCode ) && ( ucFunctionCode <= 127 ) )
+ {
+ ENTER_CRITICAL_SECTION( );
+ if( pxHandler != NULL )
+ {
+ for( i = 0; i < CONFIG_MB_FUNC_HANDLERS_MAX; i++ )
+ {
+ if( ( xFuncHandlers[i].pxHandler == NULL ) ||
+ ( xFuncHandlers[i].pxHandler == pxHandler ) )
+ {
+ xFuncHandlers[i].ucFunctionCode = ucFunctionCode;
+ xFuncHandlers[i].pxHandler = pxHandler;
+ break;
+ }
+ }
+ eStatus = ( i != CONFIG_MB_FUNC_HANDLERS_MAX ) ? MB_ENOERR : MB_ENORES;
+ }
+ else
+ {
+ for( i = 0; i < CONFIG_MB_FUNC_HANDLERS_MAX; i++ )
+ {
+ if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
+ {
+ xFuncHandlers[i].ucFunctionCode = 0;
+ xFuncHandlers[i].pxHandler = NULL;
+ break;
+ }
+ }
+ /* Remove can't fail. */
+ eStatus = MB_ENOERR;
+ }
+ EXIT_CRITICAL_SECTION( );
+ }
+ else
+ {
+ eStatus = MB_EINVAL;
+ }
+ return eStatus;
+}
+
+
+eMBErrorCode
+eMBClose( void )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+
+ if( eMBState == STATE_DISABLED )
+ {
+ if( pvMBFrameCloseCur != NULL )
+ {
+ pvMBFrameCloseCur( );
+ }
+ }
+ else
+ {
+ eStatus = MB_EILLSTATE;
+ }
+ return eStatus;
+}
+
+eMBErrorCode
+eMBEnable( void )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+
+ if( eMBState == STATE_DISABLED )
+ {
+ /* Activate the protocol stack. */
+ pvMBFrameStartCur( );
+ eMBState = STATE_ENABLED;
+ }
+ else
+ {
+ eStatus = MB_EILLSTATE;
+ }
+ return eStatus;
+}
+
+eMBErrorCode
+eMBDisable( void )
+{
+ eMBErrorCode eStatus;
+
+ if( eMBState == STATE_ENABLED )
+ {
+ pvMBFrameStopCur( );
+ eMBState = STATE_DISABLED;
+ eStatus = MB_ENOERR;
+ }
+ else if( eMBState == STATE_DISABLED )
+ {
+ eStatus = MB_ENOERR;
+ }
+ else
+ {
+ eStatus = MB_EILLSTATE;
+ }
+ return eStatus;
+}
+
+eMBErrorCode
+eMBPoll( void )
+{
+ static uint8_t *ucMBFrame;
+ static uint8_t ucRcvAddress;
+ static uint8_t ucFunctionCode;
+ static uint16_t usLength;
+ static eMBException eException;
+
+ int i;
+ eMBErrorCode eStatus = MB_ENOERR;
+ eMBEventType eEvent;
+
+ /* Check if the protocol stack is ready. */
+ if( eMBState != STATE_ENABLED )
+ {
+ return MB_EILLSTATE;
+ }
+
+ /* Check if there is a event available. If not return control to caller.
+ * Otherwise we will handle the event. */
+ if( xMBPortEventGet( &eEvent ) == true )
+ {
+ switch ( eEvent )
+ {
+ case EV_READY:
+ break;
+
+ case EV_FRAME_RECEIVED:
+ eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
+ if( eStatus == MB_ENOERR )
+ {
+ /* Check if the frame is for us. If not ignore the frame. */
+ if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )
+ {
+ ( void )xMBPortEventPost( EV_EXECUTE );
+ }
+ }
+ break;
+
+ case EV_EXECUTE:
+ ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
+ eException = MB_EX_ILLEGAL_FUNCTION;
+ for( i = 0; i < CONFIG_MB_FUNC_HANDLERS_MAX; i++ )
+ {
+ /* No more function handlers registered. Abort. */
+ if( xFuncHandlers[i].ucFunctionCode == 0 )
+ {
+ break;
+ }
+ else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
+ {
+ eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
+ break;
+ }
+ }
+
+ /* If the request was not sent to the broadcast address we
+ * return a reply. */
+ if( ucRcvAddress != MB_ADDRESS_BROADCAST )
+ {
+ if( eException != MB_EX_NONE )
+ {
+ /* An exception occured. Build an error frame. */
+ usLength = 0;
+ ucMBFrame[usLength++] = ( uint8_t )( ucFunctionCode | MB_FUNC_ERROR );
+ ucMBFrame[usLength++] = eException;
+ }
+ if( ( eMBCurrentMode == MB_ASCII ) && CONFIG_MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS )
+ {
+ vMBPortTimersDelay( CONFIG_MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS );
+ }
+ eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
+ }
+ break;
+
+ case EV_FRAME_SENT:
+ break;
+ }
+ }
+ return MB_ENOERR;
+}
diff --git a/apps/modbus/nuttx/Make.defs b/apps/modbus/nuttx/Make.defs
new file mode 100644
index 000000000..96484217b
--- /dev/null
+++ b/apps/modbus/nuttx/Make.defs
@@ -0,0 +1,40 @@
+############################################################################
+# apps/modbus/nuttx/Make.defs
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+CSRCS += portevent.c portother.c portserial.c porttimer.c
+
+DEPPATH += --dep-path nuttx
+VPATH += :nuttx
+CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/nuttx}
diff --git a/apps/modbus/nuttx/port.h b/apps/modbus/nuttx/port.h
new file mode 100644
index 000000000..d958791d9
--- /dev/null
+++ b/apps/modbus/nuttx/port.h
@@ -0,0 +1,77 @@
+/*
+ * FreeModbus Libary: NuttX Port
+ * Based on the FreeModbus Linux port by:
+ *
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * File: $Id: port.h,v 1.1 2006/08/01 20:58:49 wolti Exp $
+ */
+
+#ifndef __APPS_MODBUS_NUTTX_PORT_H
+#define __APPS_MODBUS_NUTTX_PORT_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <assert.h>
+
+/* ----------------------- Defines ------------------------------------------*/
+
+#define INLINE
+#define PR_BEGIN_EXTERN_C extern "C" {
+#define PR_END_EXTERN_C }
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+
+#define ENTER_CRITICAL_SECTION( ) vMBPortEnterCritical()
+#define EXIT_CRITICAL_SECTION( ) vMBPortExitCritical()
+
+#define MB_PORT_HAS_CLOSE 1
+
+#ifndef true
+# define true true
+#endif
+
+#ifndef false
+# define false false
+#endif
+
+/* ----------------------- Type definitions ---------------------------------*/
+
+typedef enum
+{
+ MB_LOG_ERROR = 0,
+ MB_LOG_WARN = 1,
+ MB_LOG_INFO = 2,
+ MB_LOG_DEBUG = 3
+} eMBPortLogLevel;
+
+/* ----------------------- Function prototypes ------------------------------*/
+
+void vMBPortEnterCritical(void);
+void vMBPortExitCritical(void);
+void vMBPortLog(eMBPortLogLevel eLevel, const char * szModule,
+ const char * szFmt, ...);
+void vMBPortTimerPoll(void);
+bool xMBPortSerialPoll(void);
+bool xMBPortSerialSetTimeout(uint32_t dwTimeoutMs);
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/modbus/nuttx/portevent.c b/apps/modbus/nuttx/portevent.c
new file mode 100644
index 000000000..72c02f8ed
--- /dev/null
+++ b/apps/modbus/nuttx/portevent.c
@@ -0,0 +1,76 @@
+/*
+ * FreeModbus Libary: NuttX Port
+ * Based on the FreeModbus Linux port by:
+ *
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * File: $Id: portevent.c,v 1.1 2006/08/01 20:58:49 wolti Exp $
+ */
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbport.h>
+
+#include "port.h"
+
+/* ----------------------- Variables ----------------------------------------*/
+static eMBEventType eQueuedEvent;
+static bool xEventInQueue;
+
+/* ----------------------- Start implementation -----------------------------*/
+bool
+xMBPortEventInit( void )
+{
+ xEventInQueue = false;
+ return true;
+}
+
+bool
+xMBPortEventPost( eMBEventType eEvent )
+{
+ xEventInQueue = true;
+ eQueuedEvent = eEvent;
+ return true;
+}
+
+bool
+xMBPortEventGet( eMBEventType * eEvent )
+{
+ bool xEventHappened = false;
+
+ if( xEventInQueue )
+ {
+ *eEvent = eQueuedEvent;
+ xEventInQueue = false;
+ xEventHappened = true;
+ }
+ else
+ {
+ /* Poll the serial device. The serial device timeouts if no
+ * characters have been received within for t3.5 during an
+ * active transmission or if nothing happens within a specified
+ * amount of time. Both timeouts are configured from the timer
+ * init functions.
+ */
+ ( void )xMBPortSerialPoll( );
+
+ /* Check if any of the timers have expired. */
+ vMBPortTimerPoll( );
+
+ }
+ return xEventHappened;
+}
diff --git a/apps/modbus/nuttx/portother.c b/apps/modbus/nuttx/portother.c
new file mode 100644
index 000000000..fef826760
--- /dev/null
+++ b/apps/modbus/nuttx/portother.c
@@ -0,0 +1,106 @@
+/*
+ * FreeModbus Libary: NuttX Port
+ * Based on the FreeModbus Linux port by:
+ *
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * File: $Id: portother.c,v 1.1 2006/08/01 20:58:49 wolti Exp $
+ */
+
+/* ----------------------- Standard includes --------------------------------*/
+
+#include <nuttx/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbport.h>
+
+/* ----------------------- Defines ------------------------------------------*/
+
+#define NELEMS(x) (sizeof((x))/sizeof((x)[0]))
+
+/* ----------------------- Static variables ---------------------------------*/
+
+static FILE *fLogFile = NULL;
+static eMBPortLogLevel eLevelMax = MB_LOG_DEBUG;
+static pthread_mutex_t xLock = PTHREAD_MUTEX_INITIALIZER;
+
+/* ----------------------- Start implementation -----------------------------*/
+
+void vMBPortLogLevel(eMBPortLogLevel eNewLevelMax)
+{
+ eLevelMax = eNewLevelMax;
+}
+
+void vMBPortLogFile(FILE * fNewLogFile)
+{
+ fLogFile = fNewLogFile;
+}
+
+void vMBPortLog(eMBPortLogLevel eLevel, const char * szModule, const char * szFmt, ...)
+{
+ char szBuf[512];
+ int i;
+ va_list args;
+ FILE *fOutput = fLogFile == NULL ? stderr : fLogFile;
+
+ static const char *arszLevel2Str[] = { "ERROR", "WARN", "INFO", "DEBUG" };
+
+ i = snprintf(szBuf, NELEMS(szBuf), "%s: %s: ", arszLevel2Str[eLevel], szModule);
+
+ if (i != 0)
+ {
+ va_start(args, szFmt);
+ i += vsnprintf(&szBuf[i], NELEMS(szBuf) - i, szFmt, args);
+ va_end(args);
+ }
+
+ if (i != 0)
+ {
+ if (eLevel <= eLevelMax)
+ {
+ fputs(szBuf, fOutput);
+ }
+ }
+}
+
+void vMBPortEnterCritical(void)
+{
+ int ret = pthread_mutex_lock(&xLock);
+ if (ret != 0)
+ {
+ vMBPortLog(MB_LOG_ERROR, "OTHER", "Locking primitive failed: %d\n", ret);
+ }
+}
+
+void vMBPortExitCritical(void)
+{
+ int ret = pthread_mutex_unlock(&xLock);
+ if (ret != 0)
+ {
+ vMBPortLog(MB_LOG_ERROR, "OTHER", "Locking primitive failed: %d\n", ret);
+ }
+}
diff --git a/apps/modbus/nuttx/portserial.c b/apps/modbus/nuttx/portserial.c
new file mode 100644
index 000000000..68c02830a
--- /dev/null
+++ b/apps/modbus/nuttx/portserial.c
@@ -0,0 +1,369 @@
+/*
+ * FreeModbus Libary: NuttX Port
+ * Based on the FreeModbus Linux port by:
+ *
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * File: $Id: portserial.c,v 1.3 2006/10/12 08:35:34 wolti Exp $
+ */
+
+/* ----------------------- Standard includes --------------------------------*/
+
+#include <nuttx/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+
+#ifdef CONFIG_SERIAL_TERMIOS
+# include <termios.h>
+#endif
+
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbport.h>
+
+/* ----------------------- Defines -----------------------------------------*/
+
+#ifdef CONFIG_MB_ASCII_ENABLED
+#define BUF_SIZE 513 /* must hold a complete ASCII frame. */
+#else
+#define BUF_SIZE 256 /* must hold a complete RTU frame. */
+#endif
+
+/* ----------------------- Static variables ---------------------------------*/
+
+static int iSerialFd = -1;
+static bool bRxEnabled;
+static bool bTxEnabled;
+
+static uint32_t ulTimeoutMs;
+static uint8_t ucBuffer[BUF_SIZE];
+static int uiRxBufferPos;
+static int uiTxBufferPos;
+
+#ifdef CONFIG_SERIAL_TERMIOS
+static struct termios xOldTIO;
+#endif
+
+/* ----------------------- Function prototypes ------------------------------*/
+
+static bool prvbMBPortSerialRead(uint8_t *pucBuffer, uint16_t usNBytes, uint16_t *usNBytesRead);
+static bool prvbMBPortSerialWrite(uint8_t *pucBuffer, uint16_t usNBytes);
+
+/* ----------------------- Begin implementation -----------------------------*/
+
+void vMBPortSerialEnable(bool bEnableRx, bool bEnableTx)
+{
+ /* it is not allowed that both receiver and transmitter are enabled. */
+
+ ASSERT(!bEnableRx || !bEnableTx);
+
+ if (bEnableRx)
+ {
+#ifdef CONFIG_SERIAL_TERMIOS
+ (void)tcflush(iSerialFd, TCIFLUSH);
+#endif
+ uiRxBufferPos = 0;
+ bRxEnabled = true;
+ }
+ else
+ {
+ bRxEnabled = false;
+ }
+
+ if (bEnableTx)
+ {
+ bTxEnabled = true;
+ uiTxBufferPos = 0;
+ }
+ else
+ {
+ bTxEnabled = false;
+ }
+}
+
+bool xMBPortSerialInit(uint8_t ucPort, speed_t ulBaudRate,
+ uint8_t ucDataBits, eMBParity eParity)
+{
+ char szDevice[16];
+ bool bStatus = true;
+
+#ifdef CONFIG_SERIAL_TERMIOS
+ struct termios xNewTIO;
+#endif
+
+ snprintf(szDevice, 16, "/dev/ttyS%d", ucPort);
+
+ if ((iSerialFd = open(szDevice, O_RDWR | O_NOCTTY)) < 0)
+ {
+ vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't open serial port %s: %d\n",
+ szDevice, errno);
+ }
+
+#ifdef CONFIG_SERIAL_TERMIOS
+ else if (tcgetattr(iSerialFd, &xOldTIO) != 0)
+ {
+ vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't get settings from port %s: %d\n",
+ szDevice, errno);
+ }
+ else
+ {
+ bzero(&xNewTIO, sizeof(struct termios));
+
+ xNewTIO.c_iflag |= IGNBRK | INPCK;
+ xNewTIO.c_cflag |= CREAD | CLOCAL;
+ switch (eParity)
+ {
+ case MB_PAR_NONE:
+ break;
+ case MB_PAR_EVEN:
+ xNewTIO.c_cflag |= PARENB;
+ break;
+ case MB_PAR_ODD:
+ xNewTIO.c_cflag |= PARENB | PARODD;
+ break;
+ default:
+ bStatus = false;
+ }
+
+ switch (ucDataBits)
+ {
+ case 8:
+ xNewTIO.c_cflag |= CS8;
+ break;
+ case 7:
+ xNewTIO.c_cflag |= CS7;
+ break;
+ default:
+ bStatus = false;
+ }
+
+ if (bStatus)
+ {
+ /* Set the new baud. The following might be compatible with other
+ * OSs for the following reason.
+ *
+ * (1) In NuttX, cfset[i|o]speed always return OK so failures will
+ * really only be reported when tcsetattr() is called.
+ * (2) NuttX does not support separate input and output speeds so it
+ * is not necessary to call both cfsetispeed() and
+ * cfsetospeed(), and
+ * (3) In NuttX, the input value to cfiset[i|o]speed is not
+ * encoded, but is the absolute baud value. The following might
+ * not be
+ */
+
+ if (cfsetispeed(&xNewTIO, ulBaudRate) != 0 /* || cfsetospeed(&xNewTIO, ulBaudRate) != 0 */)
+ {
+ vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %d\n",
+ ulBaudRate, szDevice, errno);
+ }
+ else if (tcsetattr(iSerialFd, TCSANOW, &xNewTIO) != 0)
+ {
+ vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't set settings for port %s: %d\n",
+ szDevice, errno);
+ }
+ else
+ {
+ vMBPortSerialEnable(false, false);
+ bStatus = true;
+ }
+ }
+ }
+#endif
+
+ return bStatus;
+}
+
+bool xMBPortSerialSetTimeout(uint32_t ulNewTimeoutMs)
+{
+ if (ulNewTimeoutMs > 0)
+ {
+ ulTimeoutMs = ulNewTimeoutMs;
+ }
+ else
+ {
+ ulTimeoutMs = 1;
+ }
+
+ return true;
+}
+
+void vMBPortClose(void)
+{
+ if (iSerialFd != -1)
+ {
+#ifdef CONFIG_SERIAL_TERMIOS
+ (void)tcsetattr(iSerialFd, TCSANOW, &xOldTIO);
+#endif
+ (void)close(iSerialFd);
+ iSerialFd = -1;
+ }
+}
+
+bool prvbMBPortSerialRead(uint8_t *pucBuffer, uint16_t usNBytes, uint16_t *usNBytesRead)
+{
+ bool bResult = true;
+ ssize_t res;
+ fd_set rfds;
+ struct timeval tv;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 50000;
+ FD_ZERO(&rfds);
+ FD_SET(iSerialFd, &rfds);
+
+ /* Wait until character received or timeout. Recover in case of an
+ * interrupted read system call.
+ */
+
+ do
+ {
+ if (select(iSerialFd + 1, &rfds, NULL, NULL, &tv) == -1)
+ {
+ if (errno != EINTR)
+ {
+ bResult = false;
+ }
+ }
+ else if (FD_ISSET(iSerialFd, &rfds))
+ {
+ if ((res = read(iSerialFd, pucBuffer, usNBytes)) == -1)
+ {
+ bResult = false;
+ }
+ else
+ {
+ *usNBytesRead = (uint16_t)res;
+ break;
+ }
+ }
+ else
+ {
+ *usNBytesRead = 0;
+ break;
+ }
+ }
+
+ while(bResult == true);
+ return bResult;
+}
+
+bool prvbMBPortSerialWrite(uint8_t *pucBuffer, uint16_t usNBytes)
+{
+ ssize_t res;
+ size_t left = (size_t) usNBytes;
+ size_t done = 0;
+
+ while(left > 0)
+ {
+ if ((res = write(iSerialFd, pucBuffer + done, left)) == -1)
+ {
+ if (errno != EINTR)
+ {
+ break;
+ }
+
+ /* call write again because of interrupted system call. */
+ continue;
+ }
+
+ done += res;
+ left -= res;
+ }
+
+ return left == 0 ? true : false;
+}
+
+bool
+xMBPortSerialPoll()
+{
+ bool bStatus = true;
+ uint16_t usBytesRead;
+ int i;
+
+ while(bRxEnabled)
+ {
+ if (prvbMBPortSerialRead(&ucBuffer[0], BUF_SIZE, &usBytesRead))
+ {
+ if (usBytesRead == 0)
+ {
+ /* timeout with no bytes. */
+ break;
+ }
+ else if (usBytesRead > 0)
+ {
+ for(i = 0; i < usBytesRead; i++)
+ {
+ /* Call the modbus stack and let him fill the buffers. */
+ (void)pxMBFrameCBByteReceived();
+ }
+ uiRxBufferPos = 0;
+ }
+ }
+ else
+ {
+ vMBPortLog(MB_LOG_ERROR, "SER-POLL", "read failed on serial device: %d\n",
+ errno);
+ bStatus = false;
+ }
+ }
+ if (bTxEnabled)
+ {
+ while(bTxEnabled)
+ {
+ (void)pxMBFrameCBTransmitterEmpty();
+ /* Call the modbus stack to let him fill the buffer. */
+ }
+ if (!prvbMBPortSerialWrite(&ucBuffer[0], uiTxBufferPos))
+ {
+ vMBPortLog(MB_LOG_ERROR, "SER-POLL", "write failed on serial device: %d\n",
+ errno);
+ bStatus = false;
+ }
+ }
+
+ return bStatus;
+}
+
+bool
+xMBPortSerialPutByte(int8_t ucByte)
+{
+ ASSERT(uiTxBufferPos < BUF_SIZE);
+ ucBuffer[uiTxBufferPos] = ucByte;
+ uiTxBufferPos++;
+ return true;
+}
+
+bool
+xMBPortSerialGetByte(int8_t *pucByte)
+{
+ ASSERT(uiRxBufferPos < BUF_SIZE);
+ *pucByte = ucBuffer[uiRxBufferPos];
+ uiRxBufferPos++;
+ return true;
+}
diff --git a/apps/modbus/nuttx/porttimer.c b/apps/modbus/nuttx/porttimer.c
new file mode 100644
index 000000000..d688c4f52
--- /dev/null
+++ b/apps/modbus/nuttx/porttimer.c
@@ -0,0 +1,102 @@
+/*
+ * FreeModbus Libary: NuttX Port
+ * Based on the FreeModbus Linux port by:
+ *
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * File: $Id: porttimer.c,v 1.1 2006/08/01 20:58:50 wolti Exp $
+ */
+
+/* ----------------------- Standard includes --------------------------------*/
+#include <nuttx/config.h>
+
+#include <sys/time.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbport.h>
+
+/* ----------------------- Defines ------------------------------------------*/
+
+/* ----------------------- Static variables ---------------------------------*/
+uint32_t ulTimeOut;
+bool bTimeoutEnable;
+
+static struct timeval xTimeLast;
+
+/* ----------------------- Start implementation -----------------------------*/
+bool
+xMBPortTimersInit( uint16_t usTim1Timerout50us )
+{
+ ulTimeOut = usTim1Timerout50us / 20U;
+ if( ulTimeOut == 0 )
+ ulTimeOut = 1;
+
+ return xMBPortSerialSetTimeout( ulTimeOut );
+}
+
+void
+xMBPortTimersClose( )
+{
+ /* Does not use any hardware resources. */
+}
+
+void
+vMBPortTimerPoll( )
+{
+ uint32_t ulDeltaMS;
+ struct timeval xTimeCur;
+
+ /* Timers are called from the serial layer because we have no high
+ * res timer in Win32. */
+ if( bTimeoutEnable )
+ {
+ if( gettimeofday( &xTimeCur, NULL ) != 0 )
+ {
+ /* gettimeofday failed - retry next time. */
+ }
+ else
+ {
+ ulDeltaMS = ( xTimeCur.tv_sec - xTimeLast.tv_sec ) * 1000L +
+ ( xTimeCur.tv_usec - xTimeLast.tv_usec ) * 1000L;
+ if( ulDeltaMS > ulTimeOut )
+ {
+ bTimeoutEnable = false;
+ ( void )pxMBPortCBTimerExpired( );
+ }
+ }
+ }
+}
+
+void
+vMBPortTimersEnable( )
+{
+ int res = gettimeofday( &xTimeLast, NULL );
+
+ ASSERT( res == 0 );
+ bTimeoutEnable = true;
+}
+
+void
+vMBPortTimersDisable( )
+{
+ bTimeoutEnable = false;
+}
diff --git a/apps/modbus/rtu/Make.defs b/apps/modbus/rtu/Make.defs
new file mode 100644
index 000000000..8b9c68c77
--- /dev/null
+++ b/apps/modbus/rtu/Make.defs
@@ -0,0 +1,44 @@
+############################################################################
+# apps/modbus/rtu/Make.defs
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_MB_RTU_ENABLED),y)
+
+CSRCS += mbcrc.c mbrtu.c
+
+DEPPATH += --dep-path rtu
+VPATH += :rtu
+CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/rtu}
+
+endif
diff --git a/apps/modbus/rtu/mbcrc.c b/apps/modbus/rtu/mbcrc.c
new file mode 100644
index 000000000..82fe3c3fb
--- /dev/null
+++ b/apps/modbus/rtu/mbcrc.c
@@ -0,0 +1,98 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbcrc.c,v 1.7 2007/02/18 23:50:27 wolti Exp $
+ */
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+static const uint8_t aucCRCHi[] = {
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40
+};
+
+static const uint8_t aucCRCLo[] = {
+ 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
+ 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
+ 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
+ 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
+ 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
+ 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
+ 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
+ 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
+ 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
+ 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
+ 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
+ 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
+ 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
+ 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
+ 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
+ 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
+ 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
+ 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
+ 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
+ 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+ 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
+ 0x41, 0x81, 0x80, 0x40
+};
+
+uint16_t
+usMBCRC16( uint8_t * pucFrame, uint16_t usLen )
+{
+ uint8_t ucCRCHi = 0xFF;
+ uint8_t ucCRCLo = 0xFF;
+ int iIndex;
+
+ while( usLen-- )
+ {
+ iIndex = ucCRCLo ^ *( pucFrame++ );
+ ucCRCLo = ( uint8_t )( ucCRCHi ^ aucCRCHi[iIndex] );
+ ucCRCHi = aucCRCLo[iIndex];
+ }
+ return ( uint16_t )( ucCRCHi << 8 | ucCRCLo );
+}
diff --git a/apps/modbus/rtu/mbcrc.h b/apps/modbus/rtu/mbcrc.h
new file mode 100644
index 000000000..9ff06e25d
--- /dev/null
+++ b/apps/modbus/rtu/mbcrc.h
@@ -0,0 +1,36 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbcrc.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_CRC_H
+#define _MB_CRC_H
+
+uint16_t usMBCRC16( uint8_t * pucFrame, uint16_t usLen );
+
+#endif
diff --git a/apps/modbus/rtu/mbrtu.c b/apps/modbus/rtu/mbrtu.c
new file mode 100644
index 000000000..196473c17
--- /dev/null
+++ b/apps/modbus/rtu/mbrtu.c
@@ -0,0 +1,357 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbrtu.c,v 1.18 2007/09/12 10:15:56 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbus/mb.h>
+#include <apps/modbus/mbframe.h>
+#include <apps/modbus/mbport.h>
+
+#include "mbrtu.h"
+#include "mbcrc.h"
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_SER_PDU_SIZE_MIN 4 /*!< Minimum size of a Modbus RTU frame. */
+#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus RTU frame. */
+#define MB_SER_PDU_SIZE_CRC 2 /*!< Size of CRC field in PDU. */
+#define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
+#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
+
+/* ----------------------- Type definitions ---------------------------------*/
+typedef enum
+{
+ STATE_RX_INIT, /*!< Receiver is in initial state. */
+ STATE_RX_IDLE, /*!< Receiver is in idle state. */
+ STATE_RX_RCV, /*!< Frame is beeing received. */
+ STATE_RX_ERROR /*!< If the frame is invalid. */
+} eMBRcvState;
+
+typedef enum
+{
+ STATE_TX_IDLE, /*!< Transmitter is in idle state. */
+ STATE_TX_XMIT /*!< Transmitter is in transfer state. */
+} eMBSndState;
+
+/* ----------------------- Static variables ---------------------------------*/
+static volatile eMBSndState eSndState;
+static volatile eMBRcvState eRcvState;
+
+volatile uint8_t ucRTUBuf[MB_SER_PDU_SIZE_MAX];
+
+static volatile uint8_t *pucSndBufferCur;
+static volatile uint16_t usSndBufferCount;
+
+static volatile uint16_t usRcvBufferPos;
+
+/* ----------------------- Start implementation -----------------------------*/
+eMBErrorCode
+eMBRTUInit( uint8_t ucSlaveAddress, uint8_t ucPort, speed_t ulBaudRate, eMBParity eParity )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+ uint32_t usTimerT35_50us;
+
+ ( void )ucSlaveAddress;
+ ENTER_CRITICAL_SECTION( );
+
+ /* Modbus RTU uses 8 Databits. */
+ if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != true )
+ {
+ eStatus = MB_EPORTERR;
+ }
+ else
+ {
+ /* If baudrate > 19200 then we should use the fixed timer values
+ * t35 = 1750us. Otherwise t35 must be 3.5 times the character time.
+ */
+ if( ulBaudRate > 19200 )
+ {
+ usTimerT35_50us = 35; /* 1800us. */
+ }
+ else
+ {
+ /* The timer reload value for a character is given by:
+ *
+ * ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )
+ * = 11 * Ticks_per_1s / Baudrate
+ * = 220000 / Baudrate
+ * The reload for t3.5 is 1.5 times this value and similary
+ * for t3.5.
+ */
+ usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
+ }
+ if( xMBPortTimersInit( ( uint16_t ) usTimerT35_50us ) != true )
+ {
+ eStatus = MB_EPORTERR;
+ }
+ }
+ EXIT_CRITICAL_SECTION( );
+
+ return eStatus;
+}
+
+void
+eMBRTUStart( void )
+{
+ ENTER_CRITICAL_SECTION( );
+ /* Initially the receiver is in the state STATE_RX_INIT. we start
+ * the timer and if no character is received within t3.5 we change
+ * to STATE_RX_IDLE. This makes sure that we delay startup of the
+ * modbus protocol stack until the bus is free.
+ */
+ eRcvState = STATE_RX_INIT;
+ vMBPortSerialEnable( true, false );
+ vMBPortTimersEnable( );
+
+ EXIT_CRITICAL_SECTION( );
+}
+
+void
+eMBRTUStop( void )
+{
+ ENTER_CRITICAL_SECTION( );
+ vMBPortSerialEnable( false, false );
+ vMBPortTimersDisable( );
+ EXIT_CRITICAL_SECTION( );
+}
+
+eMBErrorCode
+eMBRTUReceive( uint8_t * pucRcvAddress, uint8_t ** pucFrame, uint16_t * pusLength )
+{
+ bool xFrameReceived = false;
+ eMBErrorCode eStatus = MB_ENOERR;
+
+ ENTER_CRITICAL_SECTION( );
+ ASSERT( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
+
+ /* Length and CRC check */
+ if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
+ && ( usMBCRC16( ( uint8_t * ) ucRTUBuf, usRcvBufferPos ) == 0 ) )
+ {
+ /* Save the address field. All frames are passed to the upper layed
+ * and the decision if a frame is used is done there.
+ */
+ *pucRcvAddress = ucRTUBuf[MB_SER_PDU_ADDR_OFF];
+
+ /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
+ * size of address field and CRC checksum.
+ */
+ *pusLength = ( uint16_t )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC );
+
+ /* Return the start of the Modbus PDU to the caller. */
+ *pucFrame = ( uint8_t * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF];
+ xFrameReceived = true;
+ }
+ else
+ {
+ eStatus = MB_EIO;
+ }
+
+ EXIT_CRITICAL_SECTION( );
+ return eStatus;
+}
+
+eMBErrorCode
+eMBRTUSend( uint8_t ucSlaveAddress, const uint8_t * pucFrame, uint16_t usLength )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+ uint16_t usCRC16;
+
+ ENTER_CRITICAL_SECTION( );
+
+ /* Check if the receiver is still in idle state. If not we where to
+ * slow with processing the received frame and the master sent another
+ * frame on the network. We have to abort sending the frame.
+ */
+ if( eRcvState == STATE_RX_IDLE )
+ {
+ /* First byte before the Modbus-PDU is the slave address. */
+ pucSndBufferCur = ( uint8_t * ) pucFrame - 1;
+ usSndBufferCount = 1;
+
+ /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
+ pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
+ usSndBufferCount += usLength;
+
+ /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
+ usCRC16 = usMBCRC16( ( uint8_t * ) pucSndBufferCur, usSndBufferCount );
+ ucRTUBuf[usSndBufferCount++] = ( uint8_t )( usCRC16 & 0xFF );
+ ucRTUBuf[usSndBufferCount++] = ( uint8_t )( usCRC16 >> 8 );
+
+ /* Activate the transmitter. */
+ eSndState = STATE_TX_XMIT;
+ vMBPortSerialEnable( false, true );
+ }
+ else
+ {
+ eStatus = MB_EIO;
+ }
+ EXIT_CRITICAL_SECTION( );
+ return eStatus;
+}
+
+bool
+xMBRTUReceiveFSM( void )
+{
+ bool xTaskNeedSwitch = false;
+ uint8_t ucByte;
+
+ ASSERT( eSndState == STATE_TX_IDLE );
+
+ /* Always read the character. */
+ ( void )xMBPortSerialGetByte( ( int8_t * ) & ucByte );
+
+ switch ( eRcvState )
+ {
+ /* If we have received a character in the init state we have to
+ * wait until the frame is finished.
+ */
+ case STATE_RX_INIT:
+ vMBPortTimersEnable( );
+ break;
+
+ /* In the error state we wait until all characters in the
+ * damaged frame are transmitted.
+ */
+ case STATE_RX_ERROR:
+ vMBPortTimersEnable( );
+ break;
+
+ /* In the idle state we wait for a new character. If a character
+ * is received the t1.5 and t3.5 timers are started and the
+ * receiver is in the state STATE_RX_RECEIVCE.
+ */
+ case STATE_RX_IDLE:
+ usRcvBufferPos = 0;
+ ucRTUBuf[usRcvBufferPos++] = ucByte;
+ eRcvState = STATE_RX_RCV;
+
+ /* Enable t3.5 timers. */
+ vMBPortTimersEnable( );
+ break;
+
+ /* We are currently receiving a frame. Reset the timer after
+ * every character received. If more than the maximum possible
+ * number of bytes in a modbus frame is received the frame is
+ * ignored.
+ */
+ case STATE_RX_RCV:
+ if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
+ {
+ ucRTUBuf[usRcvBufferPos++] = ucByte;
+ }
+ else
+ {
+ eRcvState = STATE_RX_ERROR;
+ }
+ vMBPortTimersEnable( );
+ break;
+ }
+ return xTaskNeedSwitch;
+}
+
+bool
+xMBRTUTransmitFSM( void )
+{
+ bool xNeedPoll = false;
+
+ ASSERT( eRcvState == STATE_RX_IDLE );
+
+ switch ( eSndState )
+ {
+ /* We should not get a transmitter event if the transmitter is in
+ * idle state. */
+ case STATE_TX_IDLE:
+ /* enable receiver/disable transmitter. */
+ vMBPortSerialEnable( true, false );
+ break;
+
+ case STATE_TX_XMIT:
+ /* check if we are finished. */
+ if( usSndBufferCount != 0 )
+ {
+ xMBPortSerialPutByte( ( int8_t )*pucSndBufferCur );
+ pucSndBufferCur++; /* next byte in sendbuffer. */
+ usSndBufferCount--;
+ }
+ else
+ {
+ xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
+ /* Disable transmitter. This prevents another transmit buffer
+ * empty interrupt. */
+ vMBPortSerialEnable( true, false );
+ eSndState = STATE_TX_IDLE;
+ }
+ break;
+ }
+
+ return xNeedPoll;
+}
+
+bool
+xMBRTUTimerT35Expired( void )
+{
+ bool xNeedPoll = false;
+
+ switch ( eRcvState )
+ {
+ /* Timer t35 expired. Startup phase is finished. */
+ case STATE_RX_INIT:
+ xNeedPoll = xMBPortEventPost( EV_READY );
+ break;
+
+ /* A frame was received and t35 expired. Notify the listener that
+ * a new frame was received. */
+ case STATE_RX_RCV:
+ xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
+ break;
+
+ /* An error occured while receiving the frame. */
+ case STATE_RX_ERROR:
+ break;
+
+ /* Function called in an illegal state. */
+ default:
+ ASSERT( ( eRcvState == STATE_RX_INIT ) ||
+ ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
+ }
+
+ vMBPortTimersDisable( );
+ eRcvState = STATE_RX_IDLE;
+
+ return xNeedPoll;
+}
diff --git a/apps/modbus/rtu/mbrtu.h b/apps/modbus/rtu/mbrtu.h
new file mode 100644
index 000000000..ca35b94a7
--- /dev/null
+++ b/apps/modbus/rtu/mbrtu.h
@@ -0,0 +1,51 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbrtu.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_RTU_H
+#define _MB_RTU_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+ eMBErrorCode eMBRTUInit( uint8_t slaveAddress, uint8_t ucPort, speed_t ulBaudRate,
+ eMBParity eParity );
+void eMBRTUStart( void );
+void eMBRTUStop( void );
+eMBErrorCode eMBRTUReceive( uint8_t * pucRcvAddress, uint8_t ** pucFrame, uint16_t * pusLength );
+eMBErrorCode eMBRTUSend( uint8_t slaveAddress, const uint8_t * pucFrame, uint16_t usLength );
+bool xMBRTUReceiveFSM( void );
+bool xMBRTUTransmitFSM( void );
+bool xMBRTUTimerT15Expired( void );
+bool xMBRTUTimerT35Expired( void );
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/modbus/tcp/Make.defs b/apps/modbus/tcp/Make.defs
new file mode 100644
index 000000000..30860be3a
--- /dev/null
+++ b/apps/modbus/tcp/Make.defs
@@ -0,0 +1,44 @@
+############################################################################
+# apps/modbus/tcp/Make.defs
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_MB_TCP_ENABLED),y)
+
+CSRCS += mbtcp.c
+
+DEPPATH += --dep-path tcp
+VPATH += :tcp
+CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/tcp}
+
+endif
diff --git a/apps/modbus/tcp/mbtcp.c b/apps/modbus/tcp/mbtcp.c
new file mode 100644
index 000000000..b841f078a
--- /dev/null
+++ b/apps/modbus/tcp/mbtcp.c
@@ -0,0 +1,159 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbtcp.c,v 1.3 2006/12/07 22:10:34 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include <nuttx/config.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include <apps/modbusmb.h>
+#include <apps/modbusmbframe.h>
+#include <apps/modbusmbport.h>
+
+#include "mbtcp.h"
+
+#ifdef CONFIG_MB_TCP_ENABLED
+
+/* ----------------------- Defines ------------------------------------------*/
+
+/* ----------------------- MBAP Header --------------------------------------*/
+/*
+ *
+ * <------------------------ MODBUS TCP/IP ADU(1) ------------------------->
+ * <----------- MODBUS PDU (1') ---------------->
+ * +-----------+---------------+------------------------------------------+
+ * | TID | PID | Length | UID |Code | Data |
+ * +-----------+---------------+------------------------------------------+
+ * | | | | |
+ * (2) (3) (4) (5) (6)
+ *
+ * (2) ... MB_TCP_TID = 0 (Transaction Identifier - 2 Byte)
+ * (3) ... MB_TCP_PID = 2 (Protocol Identifier - 2 Byte)
+ * (4) ... MB_TCP_LEN = 4 (Number of bytes - 2 Byte)
+ * (5) ... MB_TCP_UID = 6 (Unit Identifier - 1 Byte)
+ * (6) ... MB_TCP_FUNC = 7 (Modbus Function Code)
+ *
+ * (1) ... Modbus TCP/IP Application Data Unit
+ * (1') ... Modbus Protocol Data Unit
+ */
+
+#define MB_TCP_TID 0
+#define MB_TCP_PID 2
+#define MB_TCP_LEN 4
+#define MB_TCP_UID 6
+#define MB_TCP_FUNC 7
+
+#define MB_TCP_PROTOCOL_ID 0 /* 0 = Modbus Protocol */
+
+
+/* ----------------------- Start implementation -----------------------------*/
+eMBErrorCode
+eMBTCPDoInit( uint16_t ucTCPPort )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+
+ if( xMBTCPPortInit( ucTCPPort ) == false )
+ {
+ eStatus = MB_EPORTERR;
+ }
+ return eStatus;
+}
+
+void
+eMBTCPStart( void )
+{
+}
+
+void
+eMBTCPStop( void )
+{
+ /* Make sure that no more clients are connected. */
+ vMBTCPPortDisable( );
+}
+
+eMBErrorCode
+eMBTCPReceive( uint8_t * pucRcvAddress, uint8_t ** ppucFrame, uint16_t * pusLength )
+{
+ eMBErrorCode eStatus = MB_EIO;
+ uint8_t *pucMBTCPFrame;
+ uint16_t usLength;
+ uint16_t usPID;
+
+ if( xMBTCPPortGetRequest( &pucMBTCPFrame, &usLength ) != false )
+ {
+ usPID = pucMBTCPFrame[MB_TCP_PID] << 8U;
+ usPID |= pucMBTCPFrame[MB_TCP_PID + 1];
+
+ if( usPID == MB_TCP_PROTOCOL_ID )
+ {
+ *ppucFrame = &pucMBTCPFrame[MB_TCP_FUNC];
+ *pusLength = usLength - MB_TCP_FUNC;
+ eStatus = MB_ENOERR;
+
+ /* Modbus TCP does not use any addresses. Fake the source address such
+ * that the processing part deals with this frame.
+ */
+ *pucRcvAddress = MB_TCP_PSEUDO_ADDRESS;
+ }
+ }
+ else
+ {
+ eStatus = MB_EIO;
+ }
+ return eStatus;
+}
+
+eMBErrorCode
+eMBTCPSend( uint8_t _unused, const uint8_t * pucFrame, uint16_t usLength )
+{
+ eMBErrorCode eStatus = MB_ENOERR;
+ uint8_t *pucMBTCPFrame = ( uint8_t * ) pucFrame - MB_TCP_FUNC;
+ uint16_t usTCPLength = usLength + MB_TCP_FUNC;
+
+ /* The MBAP header is already initialized because the caller calls this
+ * function with the buffer returned by the previous call. Therefore we
+ * only have to update the length in the header. Note that the length
+ * header includes the size of the Modbus PDU and the UID Byte. Therefore
+ * the length is usLength plus one.
+ */
+ pucMBTCPFrame[MB_TCP_LEN] = ( usLength + 1 ) >> 8U;
+ pucMBTCPFrame[MB_TCP_LEN + 1] = ( usLength + 1 ) & 0xFF;
+ if( xMBTCPPortSendResponse( pucMBTCPFrame, usTCPLength ) == false )
+ {
+ eStatus = MB_EIO;
+ }
+ return eStatus;
+}
+
+#endif
diff --git a/apps/modbus/tcp/mbtcp.h b/apps/modbus/tcp/mbtcp.h
new file mode 100644
index 000000000..1ded9c5d4
--- /dev/null
+++ b/apps/modbus/tcp/mbtcp.h
@@ -0,0 +1,53 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * 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.
+ *
+ * File: $Id: mbtcp.h,v 1.2 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_TCP_H
+#define _MB_TCP_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_TCP_PSEUDO_ADDRESS 255
+
+/* ----------------------- Function prototypes ------------------------------*/
+ eMBErrorCode eMBTCPDoInit( uint16_t ucTCPPort );
+void eMBTCPStart( void );
+void eMBTCPStop( void );
+eMBErrorCode eMBTCPReceive( uint8_t * pucRcvAddress, uint8_t ** pucFrame,
+ uint16_t * pusLength );
+eMBErrorCode eMBTCPSend( uint8_t _unused, const uint8_t * pucFrame,
+ uint16_t usLength );
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
diff --git a/apps/namedapp/Kconfig b/apps/namedapp/Kconfig
new file mode 100644
index 000000000..8d8f03421
--- /dev/null
+++ b/apps/namedapp/Kconfig
@@ -0,0 +1,15 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NAMEDAPP
+ bool "Support named applications"
+ default n
+ ---help---
+ Enable support for named applications. This features assigns a string
+ name to an application. This feature is also the underlying requirement
+ to support built-in applications in the NuttShell (NSH).
+
+if NAMEDAPP
+endif
diff --git a/apps/namedapp/Make.defs b/apps/namedapp/Make.defs
new file mode 100644
index 000000000..399fefee8
--- /dev/null
+++ b/apps/namedapp/Make.defs
@@ -0,0 +1,40 @@
+############################################################################
+# apps/namedapps/Make.defs
+# Adds selected applications to apps/ build
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_NAMEDAPP),y)
+CONFIGURED_APPS += namedapp
+endif
+
diff --git a/apps/namedapp/Makefile b/apps/namedapp/Makefile
new file mode 100644
index 000000000..6b0fd6a05
--- /dev/null
+++ b/apps/namedapp/Makefile
@@ -0,0 +1,106 @@
+############################################################################
+# apps/nshlib/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
+
+# 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..36e3ace92
--- /dev/null
+++ b/apps/namedapp/binfs.c
@@ -0,0 +1,596 @@
+/****************************************************************************
+ * apps/namedapps/binfs.c
+ *
+ * Copyright (C) 2011-2012 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 <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/fs.h>
+#include <nuttx/fs/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..264fca7b9
--- /dev/null
+++ b/apps/namedapp/exec_namedapp.c
@@ -0,0 +1,187 @@
+/****************************************************************************
+ * apps/namedaps/exec_namedapp.c
+ *
+ * Copyright (C) 2011 Uros Platise. All rights reserved.
+ * Author: Uros Platise <uros.platise@isotel.eu>
+ *
+ * With updates, modifications, and general maintenance by:
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Auther: 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 <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
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: namedapp_getname
+ *
+ * Description:
+ * Return the name of the application at index in the table of named
+ * applications.
+ *
+ ****************************************************************************/
+
+const char *namedapp_getname(int index)
+{
+ if (index < 0 || index >= number_namedapps())
+ {
+ return NULL;
+ }
+
+ return namedapps[index].name;
+}
+
+/****************************************************************************
+ * Name: namedapp_isavail
+ *
+ * Description:
+ * Return the index into the table of applications for the applicaiton with
+ * the name 'appname'.
+ *
+ ****************************************************************************/
+
+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;
+}
+
+/****************************************************************************
+ * Name: namedapp_isavail
+ *
+ * Description:
+ * Execute the application with name 'appname', providing the arguments
+ * in the argv[] array.
+ *
+ * Returned Value:
+ * On success, the task ID of the named application is returned. On
+ * failure, -1 (ERROR) is returned an the errno value is set appropriately.
+ *
+ ****************************************************************************/
+
+int exec_namedapp(FAR const char *appname, FAR const char **argv)
+{
+ pid_t pid;
+ int index;
+
+ /* Verify that an application with this name exists */
+
+ index = namedapp_isavail(appname);
+ if (index >= 0)
+ {
+ /* Disable pre-emption. This means that although we start the named
+ * application here, it will not actually run until pre-emption is
+ * re-enabled below.
+ */
+
+ sched_lock();
+
+ /* Start the named application task */
+
+ pid = TASK_CREATE(namedapps[index].name, namedapps[index].priority,
+ namedapps[index].stacksize, namedapps[index].main,
+ (argv) ? &argv[1] : (const char **)NULL);
+
+ /* If robin robin scheduling is enabled, then set the scheduling policy
+ * of the new task to SCHED_RR before it has a chance to run.
+ */
+
+#if CONFIG_RR_INTERVAL > 0
+ if (pid > 0)
+ {
+ struct sched_param param;
+
+ /* Pre-emption is disabled so the task creation and the
+ * following operation will be atomic. The priority of the
+ * new task cannot yet have changed from its initial value.
+ */
+
+ param.sched_priority = namedapps[index].priority;
+ sched_setscheduler(pid, SCHED_RR, &param);
+ }
+#endif
+ /* Now let the named application run */
+
+ sched_unlock();
+
+ /* Return the task ID of the new task if the task was sucessfully
+ * started. Otherwise, pid will be ERROR (and the errno value will
+ * be set appropriately).
+ */
+
+ return pid;
+ }
+
+ /* Return ERROR with errno set appropriately */
+
+ return ERROR;
+}
diff --git a/apps/namedapp/namedapp.c b/apps/namedapp/namedapp.c
new file mode 100644
index 000000000..d59ce6e3b
--- /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 <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 <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..7fcdf42dc
--- /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-2012 Gregory Nutt. All rights reserved.
+ * Authors: Uros Platise <uros.platise@isotel.eu>
+ * 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.
+ *
+ ****************************************************************************/
+
+#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/Kconfig b/apps/netutils/Kconfig
new file mode 100644
index 000000000..4141e5b03
--- /dev/null
+++ b/apps/netutils/Kconfig
@@ -0,0 +1,62 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+comment "Networking Utilities"
+
+menu "DHCP client"
+source "$APPSDIR/netutils/dhcpc/Kconfig"
+endmenu
+
+menu "DHCP server"
+source "$APPSDIR/netutils/dhcpd/Kconfig"
+endmenu
+
+menu "FTP client"
+source "$APPSDIR/netutils/ftpc/Kconfig"
+endmenu
+
+menu "FTP server"
+source "$APPSDIR/netutils/ftpd/Kconfig"
+endmenu
+
+menu "Name resolution"
+source "$APPSDIR/netutils/resolv/Kconfig"
+endmenu
+
+menu "SMTP"
+source "$APPSDIR/netutils/smtp/Kconfig"
+endmenu
+
+menu "TFTP client"
+source "$APPSDIR/netutils/telnetd/Kconfig"
+endmenu
+
+menu "TFTP client"
+source "$APPSDIR/netutils/tftpc/Kconfig"
+endmenu
+
+menu "THTTPD web server"
+source "$APPSDIR/netutils/thttpd/Kconfig"
+endmenu
+
+menu "uIP support library"
+source "$APPSDIR/netutils/uiplib/Kconfig"
+endmenu
+
+menu "uIP web client"
+source "$APPSDIR/netutils/webclient/Kconfig"
+endmenu
+
+menu "uIP web server"
+source "$APPSDIR/netutils/webserver/Kconfig"
+endmenu
+
+menu "UDP Discovery Utility"
+source "$APPSDIR/netutils/discover/Kconfig"
+endmenu
+
+menu "XML-RPC library"
+source "$APPSDIR/netutils/xmlrpc/Kconfig"
+endmenu
diff --git a/apps/netutils/Make.defs b/apps/netutils/Make.defs
new file mode 100644
index 000000000..ae72ab0fd
--- /dev/null
+++ b/apps/netutils/Make.defs
@@ -0,0 +1,91 @@
+############################################################################
+# apps/netutils/Make.defs
+# Adds selected applications to apps/ build
+#
+# Copyright (C) 2012 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt <gnutt@nuttx.org>
+#
+# Redistribution and use in include and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of include code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# 3. Neither the name NuttX nor the names of its contributors may be
+# used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+ifeq ($(CONFIG_NETUTILS_DHCPC),y)
+CONFIGURED_APPS += netutils/dhcpc
+endif
+
+ifeq ($(CONFIG_NETUTILS_DHCPD),y)
+CONFIGURED_APPS += netutils/dhcpd
+endif
+
+ifeq ($(CONFIG_NETUTILS_FTPC),y)
+CONFIGURED_APPS += netutils/ftpc
+endif
+
+ifeq ($(CONFIG_NETUTILS_FTPD),y)
+CONFIGURED_APPS += netutils/ftpd
+endif
+
+ifeq ($(CONFIG_NETUTILS_RESOLV),y)
+CONFIGURED_APPS += netutils/resolv
+endif
+
+ifeq ($(CONFIG_NETUTILS_SMTP),y)
+CONFIGURED_APPS += netutils/smtp
+endif
+
+ifeq ($(CONFIG_NETUTILS_TELNETD),y)
+CONFIGURED_APPS += netutils/telnetd
+endif
+
+ifeq ($(CONFIG_NETUTILS_TFTPC),y)
+CONFIGURED_APPS += netutils/tftpc
+endif
+
+ifeq ($(CONFIG_NETUTILS_THTTPD),y)
+CONFIGURED_APPS += netutils/thttpd
+endif
+
+ifeq ($(CONFIG_NETUTILS_UIPLIB),y)
+CONFIGURED_APPS += netutils/uiplib
+endif
+
+ifeq ($(CONFIG_NETUTILS_WEBCLIENT),y)
+CONFIGURED_APPS += netutils/webclient
+endif
+
+ifeq ($(CONFIG_NETUTILS_WEBSERVER),y)
+CONFIGURED_APPS += netutils/webserver
+endif
+
+ifeq ($(CONFIG_NETUTILS_DISCOVER),y)
+CONFIGURED_APPS += netutils/discover
+endif
+
+ifeq ($(CONFIG_NETUTILS_XMLRPC),y)
+CONFIGURED_APPS += netutils/xmlrpc
+endif
diff --git a/apps/netutils/Makefile b/apps/netutils/Makefile
new file mode 100644
index 000000000..058b0f629
--- /dev/null
+++ b/apps/netutils/Makefile
@@ -0,0 +1,66 @@
+############################################################################
+# apps/netutils/Makefile
+#
+# Copyright (C) 2011-2012 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
+
+ifeq ($(CONFIG_NET),y)
+SUBDIRS = uiplib dhcpc dhcpd discover ftpc ftpd resolv smtp telnetd
+SUBDIRS += webclient webserver tftpc thttpd xmlrpc
+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..e97bf5a61
--- /dev/null
+++ b/apps/netutils/README.txt
@@ -0,0 +1,112 @@
+netutils README.txt
+^^^^^^^^^^^^^^^^^^^
+
+Contents
+--------
+
+ - uIP Applications
+ - Other Network Applications
+ - Tips for Using Telnetd
+ - Tips for Using DHCPC
+
+uIP Applications
+^^^^^^^^^^^^^^^^
+
+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-based
+apps include:
+
+ dhcpc - Dynamic Host Configuration Protocol (DHCP) client. See
+ apps/include/netutils/dhcpc.h for interface information.
+ resolv - uIP DNS resolver. See apps/include/netutils/resolv.h
+ for interface information.
+ smtp - Simple Mail Transfer Protocol (SMTP) client. See
+ apps/include/netutils/smtp.h for interface information.
+ webclient - HTTP web client. See apps/include/netutils/webclient.h
+ for interface information.
+ webserver - HTTP web server. See apps/include/netutils/httpd.h
+ for interface information.
+
+You may find additional information on these apps in the uIP forum
+accessible through: http://www.sics.se/~adam/uip/index.php/Main_Page .
+Some of these (such as the uIP web server) have grown some additional
+functionality due primarily to NuttX user contributions.
+
+Other Network Applications
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Additional applications that were not part of uIP (but which are
+highly influenced by uIP) include:
+
+ dhcpd - Dynamic Host Configuration Protocol (DHCP) server. See
+ apps/include/netutils/dhcpd.h for interface information.
+ discover - This daemon is useful for discovering devices in local
+ networks, especially with DHCP configured devices. It
+ listens for UDP broadcasts which also can include a
+ device class so that groups of devices can be discovered.
+ It is also possible to address all classes with a kind of
+ broadcast discover. (Contributed by Max Holtzberg).
+ tftpc - TFTP client. See apps/include/netutils/tftp.h
+ for interface information.
+ telnetd - TELNET server. This is the Telnet logic adapted from
+ uIP and generalized for use as the front end to any
+ shell. The telnet daemon creates sessions that are
+ "wrapped" as character devices and mapped to stdin,
+ stdout, and stderr. Now the telnet session can be
+ inherited by spawned tasks.
+ ftpc - FTP client. See apps/include/ftpc.h for interface
+ information.
+ ftpd - FTP server. See apps/include/netutils/ftpd.h for interface
+ information.
+ thttpd - This is a port of Jef Poskanzer's THTTPD HTPPD server.
+ See http://acme.com/software/thttpd/ for general THTTPD
+ information. See apps/include/netutils/thttpd.h
+ for interface information. Applications using this thttpd
+ will need to provide an appconfig file in the configuration
+ directory with instruction to build applications like:
+
+ CONFIGURED_APPS += uiplib
+ CONFIGURED_APPS += thttpd
+ xmlrpc - The Embeddable Lightweight XML-RPC Server discussed at
+ http://www.drdobbs.com/web-development/an-embeddable-lightweight-xml-rpc-server/184405364
+
+Tips for Using Telnetd
+^^^^^^^^^^^^^^^^^^^^^^
+
+Telnetd is set up to be the front end for a shell. The primary use of
+Telnetd in NuttX is to support the NuttShell (NSH) Telnet front end. See
+apps/include/netutils/telnetd.h for information about how to incorporate
+Telnetd into your custom applications.
+
+To enable and link the Telnetd daemon, you need to include the following in
+in your appconfig (apps/.config) file:
+
+ CONFIGURED_APPS += uiplib
+ CONFIGURED_APPS += netutils/telnetd
+
+Also if the Telnet console is enabled, make sure that you have the following
+set in the NuttX configuration file or else the performance will be very bad
+(because there will be only one character per TCP transfer):
+
+ CONFIG_STDIO_BUFFER_SIZE Some value >= 64
+ CONFIG_STDIO_LINEBUFFER=y Since Telnetd is line oriented, line buffering
+ is optimal.
+
+Tips for Using DHCPC
+^^^^^^^^^^^^^^^^^^^^
+
+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/Kconfig b/apps/netutils/dhcpc/Kconfig
new file mode 100644
index 000000000..7453f2747
--- /dev/null
+++ b/apps/netutils/dhcpc/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_DHCPC
+ bool "DHCP client"
+ default n
+ ---help---
+ Enable support for the DHCP client.
+
+if NETUTILS_DHCPC
+endif
diff --git a/apps/netutils/dhcpc/Makefile b/apps/netutils/dhcpc/Makefile
new file mode 100644
index 000000000..29e5bd4f2
--- /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 <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 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..9801242fe
--- /dev/null
+++ b/apps/netutils/dhcpc/dhcpc.c
@@ -0,0 +1,607 @@
+/****************************************************************************
+ * netutils/dhcpc/dhcpc.c
+ *
+ * Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <nuttx/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/Kconfig b/apps/netutils/dhcpd/Kconfig
new file mode 100644
index 000000000..0d3b89f24
--- /dev/null
+++ b/apps/netutils/dhcpd/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_DHCPD
+ bool "DHCP server"
+ default n
+ ---help---
+ Enable support for the DHCP server.
+
+if NETUTILS_DHCPD
+endif
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..d9143288d
--- /dev/null
+++ b/apps/netutils/dhcpd/dhcpd.c
@@ -0,0 +1,1433 @@
+/****************************************************************************
+ * netutils/dhcpd/dhcpd.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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 <nuttx/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/discover/Kconfig b/apps/netutils/discover/Kconfig
new file mode 100644
index 000000000..e1fc0d4e0
--- /dev/null
+++ b/apps/netutils/discover/Kconfig
@@ -0,0 +1,40 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_DISCOVER
+ bool "Network Discovery Utility"
+ default n
+ depends on NET_UDP
+ select NETUTILS_UIPLIB
+ ---help---
+ Tool for discovering devices on the local network per UDP broadcast.
+
+if NETUTILS_DISCOVER
+
+config DISCOVER_STACK_SIZE
+ int "Discover Daemon Stack Size"
+ default 1024
+
+config DISCOVER_PRIORITY
+ int "Discover Daemon Priority"
+ default 50
+
+config DISCOVER_PORT
+ int "Discover Daemon Port Number"
+ default 96
+
+config DISCOVER_INTERFACE
+ string "Network Interface Name"
+ default "eth0"
+
+config DISCOVER_DEVICE_CLASS
+ hex "Network Discovery Class"
+ default 0xff
+
+config CONFIG_DISCOVER_DESCR
+ string "Discoverer Description"
+ default "NuttX"
+
+endif
diff --git a/apps/netutils/discover/Makefile b/apps/netutils/discover/Makefile
new file mode 100644
index 000000000..52099b439
--- /dev/null
+++ b/apps/netutils/discover/Makefile
@@ -0,0 +1,100 @@
+############################################################################
+# apps/netutils/discover/Makefile
+#
+# Copyright (C) 2012 Max Holtzberg. All rights reserved.
+# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+#
+# Authors: Max Holtzberg <mh@uvc.de>
+# 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
+
+# Telnet daemon
+
+ASRCS =
+CSRCS =
+
+ifeq ($(CONFIG_NET_UDP),y)
+CSRCS += discover.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/discover/README.txt b/apps/netutils/discover/README.txt
new file mode 100644
index 000000000..11aab8bf3
--- /dev/null
+++ b/apps/netutils/discover/README.txt
@@ -0,0 +1,9 @@
+apps/netutils/discover README.txt
+=================================
+
+This daemon is useful for discovering devices in local networks, especially
+with DHCP configured devices. It listens for UDP broadcasts which also can
+include a device class so that groups of devices can be discovered. It is
+also possible to address all classes with a kind of broadcast discover.
+
+See nuttx/tools/discover.py for a client example.
diff --git a/apps/netutils/discover/discover.c b/apps/netutils/discover/discover.c
new file mode 100644
index 000000000..8e2612dbb
--- /dev/null
+++ b/apps/netutils/discover/discover.c
@@ -0,0 +1,456 @@
+/****************************************************************************
+ * netutils/discover/discover.c
+ *
+ * Copyright (C) 2012 Max Holtzberg. All rights reserved.
+ * Copyright (C) 2008, 2011-2012 Gregory Nutt. All rights reserved.
+ *
+ * Authors: Max Holtzberg <mh@uvc.de>
+ * Gregory Nutt <gnutt@nuttx.org>
+ *
+ * This code is derived from the netutils/dhcpd code.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <debug.h>
+#include <errno.h>
+#include <sched.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <apps/netutils/discover.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_DISCOVER_STACK_SIZE
+# define CONFIG_DISCOVER_STACK_SIZE 1024
+#endif
+
+#ifndef CONFIG_DISCOVER_PRIORITY
+# define CONFIG_DISCOVER_PRIORITY SCHED_PRIORITY_DEFAULT
+#endif
+
+#ifndef CONFIG_DISCOVER_PORT
+# define CONFIG_DISCOVER_PORT 96
+#endif
+
+#ifndef CONFIG_DISCOVER_INTERFACE
+# define CONFIG_DISCOVER_INTERFACE "eth0"
+#endif
+
+#ifndef CONFIG_DISCOVER_DEVICE_CLASS
+# define CONFIG_DISCOVER_DEVICE_CLASS DISCOVER_ALL
+#endif
+
+#ifndef CONFIG_DISCOVER_DESCR
+# define CONFIG_DISCOVER_DESCR CONFIG_ARCH_BOARD
+#endif
+
+/* Internal Definitions *****************************************************/
+/* Discover request packet format:
+ * Byte Description
+ * 0 Protocol indentifier (0x99)
+ * 1 Request command 0x01
+ * 2 Destination device class (For querying subsets of available devices)
+ * 0xff for all devices
+ * 3 Checksum (Byte 0 - Byte 1 - Byte n) & 0xff
+ */
+
+/* Discover response packet format:
+ * Byte Description
+ * 0 Protocol indentifier (0x99)
+ * 1 Reponse command (0x02)
+ * 2-33 Device description string with 0 bytes filled
+ * 34 Checksum (Byte 0 - Byte 1 - Byte n) & 0xff
+ */
+
+#define DISCOVER_PROTO_ID 0x99
+#define DISCOVER_REQUEST 0x01
+#define DISCOVER_RESPONSE 0x02
+#define DISCOVER_ALL 0xff
+#define DISCOVER_REQUEST_SIZE 4
+#define DISCOVER_RESPONSE_SIZE 35
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef uint8_t request_t[DISCOVER_REQUEST_SIZE];
+typedef uint8_t response_t[DISCOVER_RESPONSE_SIZE];
+
+struct discover_state_s
+{
+ in_addr_t serverip;
+ request_t request;
+ response_t response;
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+struct discover_state_s g_state;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int discover_daemon(int argc, char *argv[]);
+static inline int discover_socket(void);
+static inline int discover_openlistener(void);
+static inline int discover_openresponder(void);
+static inline int discover_parse(request_t packet);
+static inline int discover_respond(in_addr_t *ipaddr);
+static inline void discover_initresponse(void);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline void discover_initresponse()
+{
+ int chk = 0;
+ int i;
+
+ g_state.response[0] = DISCOVER_PROTO_ID;
+ g_state.response[1] = DISCOVER_RESPONSE;
+
+ strncpy((char*) &g_state.response[2], CONFIG_DISCOVER_DESCR,
+ DISCOVER_RESPONSE_SIZE-3);
+
+ for (i = 0; i < DISCOVER_RESPONSE_SIZE-1; i++)
+ {
+ chk -= g_state.response[i];
+ }
+
+ /* Append check sum */
+
+ g_state.response[DISCOVER_RESPONSE_SIZE-1] = chk & 0xff;
+}
+
+static int discover_daemon(int argc, char *argv[])
+{
+ int sockfd = -1;
+ int nbytes;
+ int addrlen = sizeof(struct sockaddr_in);
+ struct sockaddr_in srcaddr;
+
+ memset(&g_state, 0, sizeof(struct discover_state_s));
+ discover_initresponse();
+
+ nvdbg("Started\n");
+
+ for (;;)
+ {
+ /* Create a socket to listen for requests from DHCP clients */
+
+ if (sockfd < 0)
+ {
+ sockfd = discover_openlistener();
+ if (sockfd < 0)
+ {
+ ndbg("Failed to create socket\n");
+ break;
+ }
+ }
+
+ /* Read the next packet */
+
+ nbytes = recvfrom(sockfd, &g_state.request, sizeof(g_state.request), 0,
+ (struct sockaddr*) &srcaddr,
+ (socklen_t *) &addrlen);
+ 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;
+ }
+
+ if (discover_parse(g_state.request) != OK)
+ {
+ continue;
+ }
+
+ ndbg("Received discover from %08lx'\n", srcaddr.sin_addr.s_addr);
+
+ discover_respond(&srcaddr.sin_addr.s_addr);
+ }
+
+ return OK;
+}
+
+static inline int discover_parse(request_t packet)
+{
+ int i;
+ uint8_t chk = 0;
+
+ if (packet[0] != DISCOVER_PROTO_ID)
+ {
+ ndbg("Wrong protocol id: %d\n", packet[0]);
+ return ERROR;
+ }
+
+ if (packet[1] != DISCOVER_REQUEST)
+ {
+ ndbg("Wrong command: %d\n", packet[1]);
+ return ERROR;
+ }
+
+ if (packet[2] == 0xff || packet[2] == CONFIG_DISCOVER_DEVICE_CLASS)
+ {
+ for (i = 0; i < DISCOVER_REQUEST_SIZE-1; i++)
+ chk -= packet[i];
+
+ if ((chk & 0xff) != packet[3])
+ {
+ ndbg("Checksum does not match: %d\n", packet[3]);
+ return ERROR;
+ }
+ else
+ {
+ return OK;
+ }
+ }
+ return ERROR;
+}
+
+static inline int discover_respond(in_addr_t *ipaddr)
+{
+ struct sockaddr_in addr;
+ int sockfd;
+ int ret;
+
+ sockfd = discover_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(CONFIG_DISCOVER_PORT);
+ addr.sin_addr.s_addr = *ipaddr;
+
+ ret = sendto(sockfd, &g_state.response, sizeof(g_state.response), 0,
+ (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
+ if (ret < 0)
+ {
+ ndbg("Could not send discovery response: %d\n", errno);
+ }
+
+ close(sockfd);
+ }
+
+ return ret;
+}
+
+static inline int discover_socket()
+{
+ 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;
+}
+
+static inline int discover_openlistener()
+{
+ struct sockaddr_in addr;
+ struct ifreq req;
+ int sockfd;
+ int ret;
+
+ /* Create a socket to listen for requests from DHCP clients */
+
+ sockfd = discover_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_DISCOVER_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.serverip = ((struct sockaddr_in*)&req.ifr_addr)->sin_addr.s_addr;
+ nvdbg("serverip: %08lx\n", ntohl(g_state.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(CONFIG_DISCOVER_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;
+}
+
+static inline int discover_openresponder(void)
+{
+ struct sockaddr_in addr;
+ int sockfd;
+ int ret;
+
+ /* Create a socket for responding to discovery message */
+
+ sockfd = discover_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.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;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: discover_start
+ *
+ * Description:
+ * Start the discover daemon.
+ *
+ * Return:
+ * The process ID (pid) of the new discover daemon is returned on
+ * success; A negated errno is returned if the daemon was not successfully
+ * started.
+ *
+ ****************************************************************************/
+
+int discover_start()
+{
+ pid_t pid;
+
+ /* Then start the new daemon */
+
+ pid = TASK_CREATE("Discover daemon", CONFIG_DISCOVER_PRIORITY,
+ CONFIG_DISCOVER_STACK_SIZE, discover_daemon, NULL);
+ if (pid < 0)
+ {
+ int errval = errno;
+ ndbg("Failed to start the discover daemon: %d\n", errval);
+ return -errval;
+ }
+
+ /* Return success */
+
+ return pid;
+}
diff --git a/apps/netutils/ftpc/Kconfig b/apps/netutils/ftpc/Kconfig
new file mode 100644
index 000000000..7a63001fa
--- /dev/null
+++ b/apps/netutils/ftpc/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_FTPC
+ bool "FTP client"
+ default n
+ ---help---
+ Enable support for the FTP client.
+
+if NETUTILS_FTPC
+endif
diff --git a/apps/netutils/ftpc/Makefile b/apps/netutils/ftpc/Makefile
new file mode 100644
index 000000000..723179131
--- /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 <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_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..d65b5789f
--- /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 <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 "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..1b95ddad4
--- /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 <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 "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..e5cd48b46
--- /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 <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 "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..cb1f9e496
--- /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 <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 "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..8e8fbd2d9
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..4fa8178a7
--- /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 <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 "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..ce345a890
--- /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 <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 "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..69578d66c
--- /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 <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 "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..14ce81a61
--- /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 <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 "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(&timestamp, 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",
+ &timestamp.tm_year, &timestamp.tm_mon, &timestamp.tm_mday,
+ &timestamp.tm_hour, &timestamp.tm_min, &timestamp.tm_sec);
+ timestamp.tm_year -= 1900;
+ timestamp.tm_mon--;
+ return mktime(&timestamp);
+}
diff --git a/apps/netutils/ftpc/ftpc_getfile.c b/apps/netutils/ftpc/ftpc_getfile.c
new file mode 100644
index 000000000..add07125f
--- /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 <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 "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..3a9952daf
--- /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 <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 "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..4c630b441
--- /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 <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 "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..7334f195d
--- /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 <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 "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..4370f8dab
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..5d6c6d156
--- /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 <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 "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..3d41d8a25
--- /dev/null
+++ b/apps/netutils/ftpc/ftpc_login.c
@@ -0,0 +1,214 @@
+/****************************************************************************
+ * apps/netutils/ftpc/ftpc_login.c
+ *
+ * Copyright (C) 2011-2012 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 "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 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..32c782396
--- /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 <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 "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..6932b1489
--- /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 <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 "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..d59c4c99e
--- /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 <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 "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..7a4c2533d
--- /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 <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 "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..abda04657
--- /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 <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 "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..b2dcb9ae1
--- /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 <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 "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..b83946878
--- /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 <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 "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..ed60cfeb0
--- /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 <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 "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..f904688fd
--- /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 <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 "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..0eb9130f3
--- /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 <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 <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..17401c280
--- /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 <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 "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..50b1a6e4e
--- /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 <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 "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/ftpd/Kconfig b/apps/netutils/ftpd/Kconfig
new file mode 100644
index 000000000..43fc70dbd
--- /dev/null
+++ b/apps/netutils/ftpd/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_FTPD
+ bool "FTP server"
+ default n
+ ---help---
+ Enable support for the FTP server.
+
+if NETUTILS_FTPD
+endif
diff --git a/apps/netutils/ftpd/Makefile b/apps/netutils/ftpd/Makefile
new file mode 100644
index 000000000..84e4f79a7
--- /dev/null
+++ b/apps/netutils/ftpd/Makefile
@@ -0,0 +1,97 @@
+############################################################################
+# apps/netutils/ftpd/Makefile
+#
+# Copyright (C) 2012 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
+
+# Telnet daemon
+
+ASRCS =
+CSRCS =
+
+ifeq ($(CONFIG_NET_TCP),y)
+CSRCS += ftpd.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/ftpd/ftpd.c b/apps/netutils/ftpd/ftpd.c
new file mode 100644
index 000000000..807bd82f1
--- /dev/null
+++ b/apps/netutils/ftpd/ftpd.c
@@ -0,0 +1,4398 @@
+/****************************************************************************
+ * apps/n etutils/ftpd.c
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Includes original code as well as logic adapted from hwport_ftpd, written
+ * by Jaehyuk Cho <minzkn@minzkn.com> which is released under a BSD license.
+ *
+ * Copyright (C) hwport.com. All rights reserved.
+ * Author: Jaehyuk Cho <mailto:minzkn@minzkn.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <libgen.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arpa/inet.h>
+
+#include <apps/netutils/ftpd.h>
+
+#include "ftpd.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define __NUTTX__ 1 /* Flags some unusual NuttX dependencies */
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+/* Account functions */
+
+static FAR struct ftpd_account_s *ftpd_account_new(FAR const char *user,
+ uint8_t accountflags);
+static void ftpd_account_free(FAR struct ftpd_account_s *account);
+static int ftpd_account_setpassword(FAR struct ftpd_account_s *account,
+ FAR const char *passwd);
+static int ftpd_account_add(FAR struct ftpd_server_s *server,
+ FAR struct ftpd_account_s *account);
+static int ftpd_account_sethome(FAR struct ftpd_account_s *account,
+ FAR const char *home);
+static FAR struct ftpd_account_s *
+ ftpd_account_search_user(FAR struct ftpd_session_s *session,
+ FAR const char *user);
+static FAR struct ftpd_account_s *
+ ftpd_account_login(FAR struct ftpd_session_s *session,
+ FAR const char *user, FAR const char *passwd);
+
+/* Parsing functions */
+
+static FAR char *ftpd_strtok(bool skipspace, FAR const char *delimiters,
+ FAR char **str);
+static FAR char *ftpd_strtok_alloc(bool skipspace,
+ FAR const char *delimiters, FAR const char **str);
+
+/* Socket helpers */
+
+static int ftpd_rxpoll(int sd, int timeout);
+static int ftpd_txpoll(int sd, int timeout);
+static int ftpd_accept(int sd, FAR void *addr, FAR socklen_t *addrlen,
+ int timeout);
+static ssize_t ftpd_recv(int sd, FAR void *data, size_t size, int timeout);
+static ssize_t ftpd_send(int sd, FAR const void *data, size_t size,
+ int timeout);
+static ssize_t ftpd_response(int sd, int timeout, FAR const char *fmt, ...);
+
+static int ftpd_dataopen(FAR struct ftpd_session_s *session);
+static int ftpd_dataclose(FAR struct ftpd_session_s *session);
+static FAR struct ftpd_server_s *ftpd_openserver(int port);
+
+/* Path helpers */
+
+static int ftpd_pathignore(FAR struct ftpd_pathnode_s *currpath);
+static void ftpd_nodefree(FAR struct ftpd_pathnode_s *node);
+static FAR struct ftpd_pathnode_s *ftpd_path2node(FAR const char *path);
+static FAR char *ftpd_node2path(FAR struct ftpd_pathnode_s *node,
+ bool strip);
+static FAR struct ftpd_pathnode_s *
+ ftpd_nodeappend(FAR struct ftpd_pathnode_s *head,
+ FAR struct ftpd_pathnode_s *node, bool override);
+static int ftpd_getpath(FAR struct ftpd_session_s *session,
+ FAR const char *path, FAR char **abspath,
+ FAR char **workpath);
+
+/* Commmand helpers */
+
+static int ftpd_changedir(FAR struct ftpd_session_s *session,
+ FAR const char *rempath);
+static off_t ftpd_offsatoi(FAR const char *filename, off_t offset);
+static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype);
+static uint8_t ftpd_listoption(FAR char **param);
+static int ftpd_listbuffer(FAR struct ftpd_session_s *session,
+ FAR char *path, FAR struct stat *st, FAR char *buffer,
+ size_t buflen, unsigned int opton);
+static int fptd_listscan(FAR struct ftpd_session_s *session,
+ FAR char *path, unsigned int opton);
+static int ftpd_list(FAR struct ftpd_session_s *session,
+ unsigned int opton);
+
+/* Command handlers */
+
+static int ftpd_command_user(FAR struct ftpd_session_s *session);
+static int ftpd_command_pass(FAR struct ftpd_session_s *session);
+static int ftpd_command_syst(FAR struct ftpd_session_s *session);
+static int ftpd_command_type(FAR struct ftpd_session_s *session);
+static int ftpd_command_mode(FAR struct ftpd_session_s *session);
+static int ftpd_command_abor(FAR struct ftpd_session_s *session);
+static int ftpd_command_quit(FAR struct ftpd_session_s *session);
+static int ftpd_command_noop(FAR struct ftpd_session_s *session);
+static int ftpd_command_port(FAR struct ftpd_session_s *session);
+static int ftpd_command_eprt(FAR struct ftpd_session_s *session);
+static int ftpd_command_pwd(FAR struct ftpd_session_s *session);
+static int ftpd_command_cwd(FAR struct ftpd_session_s *session);
+static int ftpd_command_cdup(FAR struct ftpd_session_s *session);
+static int ftpd_command_rmd(FAR struct ftpd_session_s *session);
+static int ftpd_command_mkd(FAR struct ftpd_session_s *session);
+static int ftpd_command_dele(FAR struct ftpd_session_s *session);
+static int ftpd_command_pasv(FAR struct ftpd_session_s *session);
+static int ftpd_command_epsv(FAR struct ftpd_session_s *session);
+static int ftpd_command_list(FAR struct ftpd_session_s *session);
+static int ftpd_command_nlst(FAR struct ftpd_session_s *session);
+static int ftpd_command_acct(FAR struct ftpd_session_s *session);
+static int ftpd_command_size(FAR struct ftpd_session_s *session);
+static int ftpd_command_stru(FAR struct ftpd_session_s *session);
+static int ftpd_command_rnfr(FAR struct ftpd_session_s *session);
+static int ftpd_command_rnto(FAR struct ftpd_session_s *session);
+static int ftpd_command_retr(FAR struct ftpd_session_s *session);
+static int ftpd_command_stor(FAR struct ftpd_session_s *session);
+static int ftpd_command_appe(FAR struct ftpd_session_s *session);
+static int ftpd_command_rest(FAR struct ftpd_session_s *session);
+static int ftpd_command_mdtm(FAR struct ftpd_session_s *session);
+static int ftpd_command_opts(FAR struct ftpd_session_s *session);
+static int ftpd_command_site(FAR struct ftpd_session_s *session);
+static int ftpd_command_help(FAR struct ftpd_session_s *session);
+
+static int ftpd_command(FAR struct ftpd_session_s *session);
+
+/* Worker thread */
+
+static int ftpd_startworker(pthread_startroutine_t handler, FAR void *arg,
+ size_t stacksize);
+static void ftpd_freesession(FAR struct ftpd_session_s *session);
+static void ftpd_workersetup(FAR struct ftpd_session_s *session);
+static FAR void *ftpd_worker(FAR void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct ftpd_cmd_s g_ftpdcmdtab[] =
+{
+ {"USER", ftpd_command_user, 0}, /* USER <SP> <username> <CRLF> */
+ {"PASS", ftpd_command_pass, 0}, /* PASS <SP> <password> <CRLF> */
+ {"SYST", ftpd_command_syst, FTPD_CMDFLAG_LOGIN}, /* SYST <CRLF> */
+ {"TYPE", ftpd_command_type, FTPD_CMDFLAG_LOGIN}, /* TYPE <SP> <type-code> <CRLF> */
+ {"MODE", ftpd_command_mode, FTPD_CMDFLAG_LOGIN}, /* MODE <SP> <mode-code> <CRLF> */
+ {"ABOR", ftpd_command_abor, FTPD_CMDFLAG_LOGIN}, /* ABOR <CRLF> */
+ {"QUIT", ftpd_command_quit, 0}, /* QUIT <CRLF> */
+ {"NOOP", ftpd_command_noop, FTPD_CMDFLAG_LOGIN}, /* NOOP <CRLF> */
+ {"PORT", ftpd_command_port, FTPD_CMDFLAG_LOGIN}, /* PORT <SP> <host-port> <CRLF> */
+ {"EPRT", ftpd_command_eprt, FTPD_CMDFLAG_LOGIN}, /* EPRT <SP> <d> <net-prt> <d> <net-addr> <d> <tcp-port> <d> <CRLF> */
+ {"PWD" , ftpd_command_pwd , FTPD_CMDFLAG_LOGIN}, /* PWD <CRLF> */
+ {"XPWD", ftpd_command_pwd , FTPD_CMDFLAG_LOGIN}, /* XPWD <CRLF> */
+ {"CWD" , ftpd_command_cwd , FTPD_CMDFLAG_LOGIN}, /* CWD <SP> <pathname> <CRLF> */
+ {"XCWD", ftpd_command_cwd , FTPD_CMDFLAG_LOGIN}, /* XCWD <SP> <pathname> <CRLF> */
+ {"CDUP", ftpd_command_cdup, FTPD_CMDFLAG_LOGIN}, /* CDUP <CRLF> */
+ {"XCUP", ftpd_command_cdup, FTPD_CMDFLAG_LOGIN}, /* XCUP <CRLF> */
+ {"RMD" , ftpd_command_rmd , FTPD_CMDFLAG_LOGIN}, /* RMD <SP> <pathname> <CRLF> */
+ {"XRMD", ftpd_command_rmd , FTPD_CMDFLAG_LOGIN}, /* XRMD <SP> <pathname> <CRLF> */
+ {"MKD" , ftpd_command_mkd , FTPD_CMDFLAG_LOGIN}, /* MKD <SP> <pathname> <CRLF> */
+ {"XMKD", ftpd_command_mkd , FTPD_CMDFLAG_LOGIN}, /* XMKD <SP> <pathname> <CRLF> */
+ {"DELE", ftpd_command_dele, FTPD_CMDFLAG_LOGIN}, /* DELE <SP> <pathname> <CRLF> */
+ {"PASV", ftpd_command_pasv, FTPD_CMDFLAG_LOGIN}, /* PASV <CRLF> */
+ {"EPSV", ftpd_command_epsv, FTPD_CMDFLAG_LOGIN}, /* EPSV <SP> <net-prt> <CRLF> OR EPSV <SP> ALL <CRLF> */
+ {"LPSV", ftpd_command_epsv, FTPD_CMDFLAG_LOGIN}, /* LPSV ??? */
+ {"LIST", ftpd_command_list, FTPD_CMDFLAG_LOGIN}, /* LIST [<SP> <pathname>] <CRLF> */
+ {"NLST", ftpd_command_nlst, FTPD_CMDFLAG_LOGIN}, /* NLST [<SP> <pathname>] <CRLF> */
+ {"ACCT", ftpd_command_acct, FTPD_CMDFLAG_LOGIN}, /* ACCT <SP> <account-information> <CRLF> */
+ {"SIZE", ftpd_command_size, FTPD_CMDFLAG_LOGIN}, /* SIZE <SP> <pathname> <CRLF> */
+ {"STRU", ftpd_command_stru, FTPD_CMDFLAG_LOGIN}, /* STRU <SP> <structure-code> <CRLF> */
+ {"RNFR", ftpd_command_rnfr, FTPD_CMDFLAG_LOGIN}, /* RNFR <SP> <pathname> <CRLF> */
+ {"RNTO", ftpd_command_rnto, FTPD_CMDFLAG_LOGIN}, /* RNTO <SP> <pathname> <CRLF> */
+ {"RETR", ftpd_command_retr, FTPD_CMDFLAG_LOGIN}, /* RETR <SP> <pathname> <CRLF> */
+ {"STOR", ftpd_command_stor, FTPD_CMDFLAG_LOGIN}, /* STOR <SP> <pathname> <CRLF> */
+ {"APPE", ftpd_command_appe, FTPD_CMDFLAG_LOGIN}, /* APPE <SP> <pathname> <CRLF> */
+ {"REST", ftpd_command_rest, FTPD_CMDFLAG_LOGIN}, /* REST <SP> <marker> <CRLF> */
+ {"MDTM", ftpd_command_mdtm, FTPD_CMDFLAG_LOGIN}, /* MDTM <SP> <pathname> <CRLF> */
+ {"OPTS", ftpd_command_opts, FTPD_CMDFLAG_LOGIN}, /* OPTS <SP> <option> <value> <CRLF> */
+ {"SITE", ftpd_command_site, FTPD_CMDFLAG_LOGIN}, /* SITE <SP> <string> <CRLF> */
+ {"HELP", ftpd_command_help, FTPD_CMDFLAG_LOGIN}, /* HELP [<SP> <string>] <CRLF> */
+#if 0
+ {"SMNT", ftpd_command_smnt, FTPD_CMDFLAG_LOGIN}, /* SMNT <SP> <pathname> <CRLF> */
+ {"REIN", ftpd_command_rein, FTPD_CMDFLAG_LOGIN}, /* REIN <CRLF> */
+ {"STOU", ftpd_command_stou, FTPD_CMDFLAG_LOGIN}, /* STOU <CRLF> */
+ {"STAT", ftpd_command_stat, FTPD_CMDFLAG_LOGIN}, /* STAT [<SP> <pathname>] <CRLF> */
+ {"ALLO", ftpd_command_stat, FTPD_CMDFLAG_LOGIN}, /* ALLO <SP> <decimal-integer> [<SP> R <SP> <decimal-integer>] <CRLF> */
+#endif
+ {NULL, (ftpd_cmdhandler_t)0, 0}
+};
+
+static const char g_cdup[] = "..";
+static const char g_respfmt1[] = "%03u%c%s\r\n"; /* Integer, character, string */
+static const char g_respfmt2[] = "%03u%c%s%s\r\n"; /* Integer, character, two strings */
+
+static const char *g_monthtab[] =
+{
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const char *g_ftpdhelp[] =
+{
+ "The following commands are recognized (* =>'s unimplemented):",
+ "CWD XCWD CDUP XCUP SMNT* QUIT PORT PASV",
+ "EPRT* EPSV* ALLO* RNFR RNTO DELE MDTM RMD",
+ "XRMD MKD XMKD PWD XPWD SIZE SYST HELP",
+ "NOOP FEAT* OPTS AUTH* CCC* CONF* ENC* MIC*",
+ "PBSZ* PROT* TYPE STRU* MODE* RETR STOR STOU*",
+ "APPE REST ABOR USER PASS ACCT* REIN* LIST",
+ "NLST STAT* SITE* MLSD* MLST*",
+ "Direct comments to " CONFIG_FTPD_VENDORID,
+ NULL
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Account Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: ftpd_account_new
+ ****************************************************************************/
+
+static FAR struct ftpd_account_s *ftpd_account_new(FAR const char *user,
+ uint8_t accountflags)
+{
+ FAR struct ftpd_account_s *ret;
+ size_t usersize;
+ size_t allocsize;
+
+ /* Get the size of the allocation */
+
+ allocsize = sizeof(struct ftpd_account_s);
+ if (!user)
+ {
+ usersize = 0;
+ }
+ else
+ {
+ usersize = strlen(user);
+ allocsize += usersize + 1;
+ }
+
+ /* Allocate the account and user string */
+
+ ret = (struct ftpd_account_s *)zalloc(allocsize);
+ if (!ret)
+ {
+ ndbg("Failed to allocate account\n");
+ return NULL;
+ }
+
+ /* Initialize the account and user string */
+
+ ret->flags = accountflags;
+
+ if (user)
+ {
+ ret->user = (FAR char *)&ret[1];
+ strcpy(ret->user, user);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_account_free
+ ****************************************************************************/
+
+static void ftpd_account_free(FAR struct ftpd_account_s *account)
+{
+ struct ftpd_account_s *prev;
+ DEBUGASSERT(account);
+
+ /* Back up to the first entry in the list */
+
+ while (account->blink)
+ {
+ account = account->blink;
+ }
+
+ /* Then free the entire list */
+
+ while (account)
+ {
+ prev = account;
+ account = account->flink;
+
+ /* Free the home path and the password */
+
+ if (prev->home)
+ {
+ free(prev->home);
+ }
+
+ if (prev->password)
+ {
+ free(prev->password);
+ }
+
+ /* Then free the container itself */
+
+ free(prev);
+ }
+}
+
+/****************************************************************************
+ * Name: ftpd_account_setpassword
+ ****************************************************************************/
+
+static int ftpd_account_setpassword(FAR struct ftpd_account_s *account,
+ FAR const char *passwd)
+{
+ FAR char *temp;
+ DEBUGASSERT(account);
+
+ /* Make of copy of the password string (if it is non-null) */
+
+ temp = NULL;
+ if (passwd)
+ {
+ temp = strdup(passwd);
+ if (!temp)
+ {
+ return -ENOMEM;
+ }
+ }
+
+ /* Free any existing password string */
+
+ if (account->password)
+ {
+ free(account->password);
+ }
+
+ /* Set the new password */
+
+ account->password = temp;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpd_account_add
+ ****************************************************************************/
+
+static int ftpd_account_add(FAR struct ftpd_server_s *server,
+ FAR struct ftpd_account_s *account)
+{
+ FAR struct ftpd_account_s *head;
+ FAR struct ftpd_account_s *tail;
+ DEBUGASSERT(server && account);
+
+ /* Find the beginning of the list */
+
+ head = account;
+ while (head->blink)
+ {
+ head = head->blink;
+ }
+
+ /* Find the tail of the list */
+
+ tail = account;
+ while (tail->flink)
+ {
+ tail = tail->flink;
+ }
+
+ /* Handle the case where the list is empty */
+
+ if (!server->head)
+ {
+ server->head = head;
+ }
+ else
+ {
+ head->blink = server->tail;
+ server->tail->flink = head;
+ }
+
+ server->tail = tail;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpd_account_sethome
+ ****************************************************************************/
+
+static int ftpd_account_sethome(FAR struct ftpd_account_s *account,
+ FAR const char *home)
+{
+ FAR char *temp;
+
+ DEBUGASSERT(account);
+
+ /* Make a copy of the home path string (unless it is NULL) */
+
+ temp = NULL;
+ if (home)
+ {
+ temp = strdup(home);
+ if (!temp)
+ {
+ return -ENOMEM;
+ }
+ }
+
+ /* Free any existing home path string */
+
+ if (account->home)
+ {
+ free(account->home);
+ }
+
+ /* And set the new home path string */
+
+ account->home = temp;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpd_account_search_user
+ ****************************************************************************/
+
+static FAR struct ftpd_account_s *
+ftpd_account_search_user(FAR struct ftpd_session_s *session,
+ FAR const char *user)
+{
+ FAR struct ftpd_account_s *newaccount = NULL;
+ FAR struct ftpd_account_s *account;
+ uint8_t accountflags;
+
+ account = session->head;
+ while (account)
+ {
+ accountflags = account->flags;
+
+ /* Check if the account has a user */
+
+ if (!account->user)
+ {
+ /* No.. The account has no user, was a user name provided? */
+
+ if (!user)
+ {
+ /* Yes.. create the account */
+
+ newaccount = ftpd_account_new(NULL, accountflags);
+ if (newaccount)
+ {
+ if (ftpd_account_setpassword(newaccount, account->password) < 0)
+ {
+ ftpd_account_free(newaccount);
+ newaccount = NULL;
+ }
+ else if (ftpd_account_sethome(newaccount, account->home) < 0)
+ {
+ ftpd_account_free(newaccount);
+ newaccount = NULL;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Was a user name provided? */
+
+ else if (user)
+ {
+ /* Check if matches the user name on the account */
+
+ if (strcmp(user, (FAR const char *)account->user) == 0)
+ {
+ /* Yes.. create the account */
+
+ newaccount = ftpd_account_new(account->user, accountflags);
+ if (newaccount)
+ {
+ if (ftpd_account_setpassword(newaccount, account->password) != 0)
+ {
+ ftpd_account_free(newaccount);
+ newaccount = NULL;
+ }
+ else if (ftpd_account_sethome(newaccount, account->home) != 0)
+ {
+ ftpd_account_free(newaccount);
+ newaccount = NULL;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Try the next account */
+
+ account = account->flink;
+ }
+
+ return newaccount;
+}
+
+/****************************************************************************
+ * Name: ftpd_account_login
+ ****************************************************************************/
+
+static FAR struct ftpd_account_s *
+ftpd_account_login(FAR struct ftpd_session_s *session,
+ FAR const char *user, FAR const char *passwd)
+{
+ FAR struct ftpd_account_s *account;
+ bool pwvalid;
+ FAR char *home;
+
+ account = ftpd_account_search_user(session, user);
+ if (!account)
+ {
+ return NULL;
+ }
+
+ if (!account->password)
+ {
+ if (!passwd)
+ {
+ pwvalid = true;
+ }
+ else if (passwd[0] == '\0')
+ {
+ pwvalid = true;
+ }
+ else
+ {
+ pwvalid = false;
+ }
+ }
+ else if (!passwd)
+ {
+ pwvalid = false;
+ }
+ else if (strcmp(passwd, (FAR const char *)account->password) == 0)
+ {
+ pwvalid = true;
+ }
+ else
+ {
+ pwvalid = false;
+ }
+
+ if (!pwvalid)
+ {
+ ftpd_account_free(account);
+ return NULL;
+ }
+
+ home = account->home;
+ if (!home)
+ {
+ home = getenv("HOME");
+ }
+
+ if ((account->flags & FTPD_ACCOUNTFLAG_ADMIN) != 0)
+ {
+ /* admin user */
+
+ session->home = strdup("/");
+ session->work = strdup(!home ? "/" : home);
+ }
+ else
+ {
+ /* normal user */
+
+ session->home = strdup(!home ? "/" : home);
+ session->work = strdup("/");
+ }
+
+ ftpd_account_free(account);
+ return account;
+}
+
+/****************************************************************************
+ * Parsing Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: ftpd_strtok
+ ****************************************************************************/
+
+static FAR char *ftpd_strtok(bool skipspace, FAR const char *delimiters,
+ FAR char **str)
+{
+ FAR const char *dptr;
+ FAR char *sptr;
+ FAR char *ret;
+
+ sptr = *str;
+
+ /* Skip any leading spaces */
+
+ if (skipspace)
+ {
+ while (isspace(*sptr))
+ {
+ sptr++;
+ }
+ }
+
+ ret = sptr;
+
+ /* The following is an implementation of strtok. It does not modify the
+ * original string as strtok does, however.
+ */
+
+ while (*sptr != '\0')
+ {
+ dptr = delimiters;
+ while (*sptr != *dptr && *dptr != '\0')
+ {
+ dptr++;
+ }
+
+ if (*sptr == *dptr)
+ {
+ break;
+ }
+
+ sptr++;
+ }
+
+ /* Save the place where we will resuming searching */
+
+ *str = sptr;
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_strtok_alloc
+ ****************************************************************************/
+
+static FAR char *ftpd_strtok_alloc(bool skipspace, FAR const char *delimiters,
+ FAR const char **str)
+{
+ FAR const char *sptr;
+ FAR const char *left;
+ FAR const char *right;
+ FAR const char *dptr;
+ FAR char *ret;
+ size_t tokenlen;
+
+ sptr = *str;
+
+ if (skipspace)
+ {
+ while (isspace(*sptr))
+ {
+ sptr++;
+ }
+ }
+
+ right = sptr;
+ left = sptr;
+
+ /* The the following logic is similar to strtok(), but only bounds the
+ * token of interest between left (the first character of the substring)
+ * and right (the character after the end of the substring).
+ */
+
+ while (*sptr != '\0')
+ {
+ dptr = delimiters;
+ while (*sptr != *dptr && *dptr != '\0')
+ {
+ dptr++;
+ }
+
+ if (*sptr == *dptr)
+ {
+ break;
+ }
+
+ sptr++;
+
+ /* Adjust the right pointer but ignoring any trailing spaces if
+ * 'skipspace' is selected.
+ */
+
+ if (!skipspace || !isspace(*sptr))
+ {
+ right = sptr;
+ }
+ }
+
+ /* Allocate memory large enough to hold the entire sub-string (including
+ * the NUL terminator.
+ */
+
+ tokenlen = (size_t)(right - left);
+ ret = (FAR char *)malloc(tokenlen + 1);
+ if (ret)
+ {
+ if (tokenlen > 0)
+ {
+ memcpy(ret, left, tokenlen);
+ }
+ ret[tokenlen] = '\0';
+ }
+
+ /* Save the place where we will resuming searching */
+
+ *str = sptr;
+ return ret;
+}
+
+/****************************************************************************
+ * Socket Helpers
+ ****************************************************************************/
+/****************************************************************************
+ * Name: ftpd_rxpoll
+ ****************************************************************************/
+
+static int ftpd_rxpoll(int sd, int timeout)
+{
+ struct pollfd fds[1];
+ int ret;
+
+ /* Set up the poll */
+
+ fds[0].fd = sd;
+ fds[0].events = POLLIN;
+ fds[0].revents = 0;
+
+ /* Perform the poll. */
+
+ ret = poll(fds, 1, timeout);
+
+ /* Handle the result of the poll. On success, poll returns the number
+ * of structures that have nonzero revents fields. A value of 0 indicates
+ * that the call timed out and no file descriptors were ready. On error,
+ * -1 is returned, and errno is set appropriately:
+ */
+
+ if (ret == 0)
+ {
+ //nvdbg("poll() timed out\n");
+ return -ETIMEDOUT;
+ }
+ else if (ret < 0)
+ {
+ int errval = errno;
+ nvdbg("poll() failed: %d\n", errval);
+ return -errval;
+ }
+ else
+ {
+ return OK;
+ }
+}
+
+/****************************************************************************
+ * Name: ftpd_txpoll
+ ****************************************************************************/
+
+static int ftpd_txpoll(int sd, int timeout)
+{
+ struct pollfd fds[1];
+ int ret;
+
+ /* Set up the poll */
+
+ fds[0].fd = sd;
+ fds[0].events = POLLOUT;
+ fds[0].revents = 0;
+
+ /* Perform the poll. */
+
+ ret = poll(fds, 1, timeout);
+
+ /* Handle the result of the poll. On success, poll returns the number
+ * of structures that have nonzero revents fields. A value of 0 indicates
+ * that the call timed out and no file descriptors were ready. On error,
+ * -1 is returned, and errno is set appropriately:
+ */
+
+ if (ret == 0)
+ {
+ nvdbg("poll() timed out\n");
+ return -ETIMEDOUT;
+ }
+ else if (ret < 0)
+ {
+ int errval = errno;
+ nvdbg("poll() failed: %d\n", errval);
+ return -errval;
+ }
+ else
+ {
+ return OK;
+ }
+}
+
+/****************************************************************************
+ * Name: ftpd_accept
+ ****************************************************************************/
+
+static int ftpd_accept(int sd, FAR void *addr, FAR socklen_t *addrlen,
+ int timeout)
+{
+ int acceptsd;
+ int ret;
+
+ /* Handle any requested timeout */
+
+ if (timeout >= 0)
+ {
+ ret = ftpd_rxpoll(sd, timeout);
+ if (ret < 0)
+ {
+ /* Only report interesting, infrequent errors (not the common timeout) */
+
+#ifdef CONFIG_DEBUG_NET
+ if (ret != -ETIMEDOUT)
+ {
+ ndbg("ftpd_rxpoll() failed: %d\n", ret);
+ }
+#endif
+ return ret;
+ }
+ }
+
+ /* Accept the connection -- waiting if necessary */
+
+ acceptsd = accept(sd, (FAR struct sockaddr *)addr, addrlen);
+ if (acceptsd < 0)
+ {
+ int errval = errno;
+ ndbg("accept() failed: %d\n", errval);
+ return -errval;
+ }
+
+ return acceptsd;
+}
+
+/****************************************************************************
+ * Name: ftpd_recv
+ ****************************************************************************/
+
+static ssize_t ftpd_recv(int sd, FAR void *data, size_t size, int timeout)
+{
+ ssize_t ret;
+ int status;
+
+ /* Handle any requested timetout */
+
+ if (timeout >= 0)
+ {
+ status = ftpd_rxpoll(sd, timeout);
+ if (status < 0)
+ {
+ nvdbg("ftpd_rxpoll: %d\n", status);
+ return (ssize_t)status;
+ }
+ }
+
+ /* Receive the data... waiting if necessary. The client side will break the
+ * connection after the file has been sent. Zero (end-of-file) should be
+ * received in this case.
+ */
+
+ ret = recv(sd, data, size, 0);
+ if (ret < 0)
+ {
+ int errval = errno;
+
+ ndbg("recv() failed: %d\n", errval);
+ return -errval;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_send
+ ****************************************************************************/
+
+static ssize_t ftpd_send(int sd, FAR const void *data, size_t size, int timeout)
+{
+ ssize_t ret;
+
+ /* Handle any requested timetout */
+
+ if (timeout >= 0)
+ {
+ int status = ftpd_txpoll(sd, timeout);
+ if (status < 0)
+ {
+ nvdbg("ftpd_rxpoll: %d\n", status);
+ return (ssize_t)status;
+ }
+ }
+
+ /* Then send the data (waiting if necessary) */
+
+ ret = send(sd, data, size, 0);
+ if (ret < 0)
+ {
+ ssize_t errval = errno;
+ ndbg("send() failed: %d\n", errval);
+ return -errval;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_response
+ ****************************************************************************/
+
+static ssize_t ftpd_response(int sd, int timeout, FAR const char *fmt, ...)
+{
+ FAR char *buffer;
+ ssize_t bytessent;
+ va_list ap;
+
+ va_start(ap, fmt);
+ avsprintf(&buffer, fmt, ap);
+ va_end(ap);
+
+ if (!buffer)
+ {
+ return -ENOMEM;
+ }
+
+ bytessent = ftpd_send(sd, buffer, strlen(buffer), timeout);
+ free(buffer);
+
+ return bytessent;
+}
+
+/****************************************************************************
+ * Name: ftpd_dataopen
+ ****************************************************************************/
+
+static int ftpd_dataopen(FAR struct ftpd_session_s *session)
+{
+ int sd;
+ int ret;
+
+ if (session->data.sd < 0)
+ {
+ /* PORT session */
+
+#ifdef CONFIG_NET_IPv6
+ if (session->data.addr.ss.ss_family == AF_INET6)
+ {
+ session->data.sd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ }
+ else
+ {
+ session->data.sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ }
+#else
+ session->data.sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+#endif
+
+ if (session->data.sd < 0)
+ {
+ int errval = errno;
+ ndbg("socket() failed: %d\n", errval);
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 451, ' ', "Socket error !");
+ return -errval;
+ }
+
+ session->data.addrlen = (socklen_t)sizeof(session->data.addr);
+ ret = connect(session->data.sd, (FAR const struct sockaddr *)(&session->data.addr),
+ session->data.addrlen);
+ if (ret < 0)
+ {
+ int errval = errno;
+ ndbg("connect() failed: %d\n", errval);
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 451, ' ', "Connect error !");
+ (void)ftpd_dataclose(session);
+ return -errval;
+ }
+
+#ifdef CONFIG_NET_HAVE_SOLINGER
+ {
+ struct linger ling;
+
+ (void)memset(&ling, 0, sizeof(ling));
+ ling.l_onoff = 1;
+ ling.l_linger = 4;
+ (void)setsockopt(session->data.sd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
+ }
+#endif
+
+ return OK;
+ }
+
+ /* PASV session */
+
+ session->data.addrlen = sizeof(session->data.addr);
+ sd = ftpd_accept(session->data.sd, (struct sockaddr *)(&session->data.addr),
+ &session->data.addrlen, -1);
+ if (sd < 0)
+ {
+ ndbg("ftpd_accept() failed: %d\n", sd);
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 451, ' ', "Accept error !");
+ (void)ftpd_dataclose(session);
+ return sd;
+ }
+
+ close(session->data.sd);
+ session->data.sd = sd;
+
+#ifdef CONFIG_NET_HAVE_SOLINGER
+ {
+ struct linger ling;
+
+ (void)memset(&ling, 0, sizeof(ling));
+ ling.l_onoff = 1;
+ ling.l_linger = 4;
+ (void)setsockopt(session->data.sd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
+ }
+#endif
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpd_dataclose
+ ****************************************************************************/
+
+static int ftpd_dataclose(FAR struct ftpd_session_s *session)
+{
+ if (session->data.sd >= 0)
+ {
+ close(session->data.sd);
+ session->data.sd = -1;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpd_openserver
+ ****************************************************************************/
+
+static FAR struct ftpd_server_s *ftpd_openserver(int port)
+{
+ FAR struct ftpd_server_s *server;
+ sa_family_t family;
+ socklen_t addrlen;
+ FAR const void *addr;
+#if defined(SOMAXCONN)
+ int backlog = SOMAXCONN;
+#else
+ int backlog = 5;
+#endif
+ int ret;
+
+ /* Allocate the server instance */
+
+ server = (FAR struct ftpd_server_s *)zalloc(sizeof(struct ftpd_server_s));
+ if (!server)
+ {
+ ndbg("Failed to allocate server\n");
+ return NULL;
+ }
+
+ /* Initialize the server instance */
+
+ server->sd = -1;
+ server->head = NULL;
+ server->tail = NULL;
+
+ /* Create the server listen socket */
+
+#ifdef CONFIG_NET_IPv6
+ server->sd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ if (server->sd < 0)
+ {
+ ftpd_close((FTPD_SESSION)server);
+ return NULL;
+ }
+
+ family = AF_INET6;
+ addrlen = (socklen_t)sizeof(server->addr.in6);
+ addr = (FAR void *)(&server->addr.in6);
+
+ server->addr.in6.sin6_family = family;
+ server->addr.in6.sin6_flowinfo = 0;
+ server->addr.in6.sin6_addr = in6addr_any;
+ server->addr.in6.sin6_port = htons(port);
+#else
+ server->sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (server->sd < 0)
+ {
+ ftpd_close((FTPD_SESSION)server);
+ return NULL;
+ }
+
+ family = AF_INET;
+ addrlen = (socklen_t)sizeof(server->addr.in4);
+ addr = (FAR void *)(&server->addr.in4);
+
+ server->addr.in4.sin_family = family;
+ server->addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
+ server->addr.in4.sin_port = htons(port);
+#endif
+
+#ifdef CONFIG_NET_HAVE_REUSEADDR
+ {
+ int reuse = 1;
+ (void)setsockopt(server->sd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+ }
+#endif
+
+ /* Bind the socket to the address */
+
+ ret = bind(server->sd, (FAR const struct sockaddr *)addr, addrlen);
+ if (ret < 0)
+ {
+ ftpd_close((FTPD_SESSION)server);
+ return NULL;
+ }
+
+ /* Listen on the socket */
+
+ ret = listen(server->sd, backlog);
+ if (ret < 0)
+ {
+ ftpd_close((FTPD_SESSION)server);
+ return NULL;
+ }
+
+ return (FTPD_SESSION)server;
+}
+
+/****************************************************************************
+ * Path Helpers
+ ****************************************************************************/
+/****************************************************************************
+ * Name: ftpd_pathignore
+ ****************************************************************************/
+
+static int ftpd_pathignore(FAR struct ftpd_pathnode_s *currpath)
+{
+ FAR struct ftpd_pathnode_s *node;
+ size_t namelen;
+
+ namelen = !currpath->name ? 0 : strlen(currpath->name);
+
+ if (namelen == 0)
+ {
+ if (currpath->blink)
+ {
+ currpath->ignore = true;
+ }
+
+ return OK;
+ }
+
+ if (strcmp(currpath->name, "..") == 0)
+ {
+ currpath->ignore = true;
+
+ node = currpath->blink;
+ while (node)
+ {
+ if (!node->ignore)
+ {
+ namelen = !node->name ? 0 : strlen(node->name);
+
+ if (namelen > 0)
+ {
+ node->ignore = true;
+ }
+ break;
+ }
+ node = node->blink;
+ }
+
+ return OK;
+ }
+
+ if (strcmp(currpath->name, ".") == 0)
+ {
+ currpath->ignore = true;
+ return OK;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name:
+ ****************************************************************************/
+
+static void ftpd_nodefree(FAR struct ftpd_pathnode_s *node)
+{
+ FAR struct ftpd_pathnode_s *prev;
+
+ while (node)
+ {
+ prev = node;
+ node = node->flink;
+
+ if (prev->name)
+ {
+ free(prev->name);
+ }
+ free(prev);
+ }
+}
+
+/****************************************************************************
+ * Name: ftpd_path2node
+ ****************************************************************************/
+
+static FAR struct ftpd_pathnode_s *ftpd_path2node(FAR const char *path)
+{
+ FAR struct ftpd_pathnode_s *head = NULL;
+ FAR struct ftpd_pathnode_s *tail = NULL;
+ FAR struct ftpd_pathnode_s *newnode;
+ FAR char *name;
+
+ if (!path)
+ {
+ return NULL;
+ }
+
+ while (path[0] != '\0')
+ {
+ name = ftpd_strtok_alloc(false, "/\\", &path);
+ if (!name)
+ {
+ break;
+ }
+
+ if (path[0] != '\0')
+ {
+ path++;
+ }
+
+ newnode = (FAR struct ftpd_pathnode_s *)malloc(sizeof(struct ftpd_pathnode_s));
+ if (!newnode)
+ {
+ free(name);
+ ftpd_nodefree(head);
+ return NULL;
+ }
+
+ newnode->blink = tail;
+ newnode->flink = NULL;
+ newnode->ignore = false;
+ newnode->name = name;
+
+ if (!tail)
+ {
+ head = newnode;
+ }
+ else
+ {
+ tail->flink = newnode;
+ }
+
+ tail = newnode;
+
+ (void)ftpd_pathignore(newnode);
+ }
+
+ return head;
+}
+
+/****************************************************************************
+ * Name: ftpd_node2path
+ ****************************************************************************/
+
+static FAR char *ftpd_node2path(FAR struct ftpd_pathnode_s *node,
+ bool strip)
+{
+ FAR struct ftpd_pathnode_s *node1;
+ FAR struct ftpd_pathnode_s *node2;
+ FAR char *path;
+ FAR size_t allocsize;
+ FAR size_t namelen;
+
+ if (!node)
+ {
+ return NULL;
+ }
+
+ allocsize = 0;
+ node1 = node;
+ while (node1)
+ {
+ if (strip)
+ {
+ if (node1->ignore)
+ {
+ node1 = node1->flink;
+ continue;
+ }
+ }
+
+ node2 = node1->flink;
+ while (strip && node2)
+ {
+ if (!node2->ignore)
+ {
+ break;
+ }
+
+ node2 = node2->flink;
+ }
+
+ namelen = !node1->name ? 0 : strlen(node1->name);
+ if (!node2)
+ {
+ if (namelen <= 0)
+ {
+ allocsize += 2;
+ }
+ else
+ {
+ allocsize += namelen +1;
+ }
+ }
+ else
+ {
+ allocsize += namelen + 1;
+ }
+
+ node1 = node1->flink;
+ }
+
+ path = (FAR char *)malloc(allocsize);
+ if (!path)
+ {
+ return NULL;
+ }
+
+ allocsize = 0;
+ node1 = node;
+ while (node1)
+ {
+ if (strip != 0)
+ {
+ if (node1->ignore)
+ {
+ node1 = node1->flink;
+ continue;
+ }
+ }
+
+ node2 = node1->flink;
+ while (strip && node2)
+ {
+ if (!node2->ignore)
+ {
+ break;
+ }
+
+ node2 = node2->flink;
+ }
+
+ namelen = !node1->name ? 0 : strlen(node1->name);
+
+ if (!node2)
+ {
+ if (namelen <= 0)
+ {
+ allocsize += sprintf(&path[allocsize], "/");
+ }
+ else
+ {
+ allocsize += sprintf(&path[allocsize], "%s", node1->name);
+ }
+ }
+ else
+ {
+ allocsize += sprintf(&path[allocsize], "%s%s", node1->name, "/");
+ }
+
+ node1 = node1->flink;
+ }
+
+ return path;
+}
+
+/****************************************************************************
+ * Name: ftpd_nodeappend
+ ****************************************************************************/
+
+static FAR struct ftpd_pathnode_s *
+ftpd_nodeappend(FAR struct ftpd_pathnode_s *head,
+ FAR struct ftpd_pathnode_s *node, bool override)
+{
+ FAR struct ftpd_pathnode_s *temp;
+
+ if (override)
+ {
+ if (node && node->name && strlen(node->name) <= 0)
+ {
+ ftpd_nodefree(head);
+ head = NULL;
+ }
+ }
+
+ if (!head)
+ {
+ if (node)
+ {
+ node->blink = NULL;
+ }
+
+ head = node;
+ node = NULL;
+ }
+
+ if (node)
+ {
+ temp = head;
+ while (temp->flink)
+ {
+ temp = temp->flink;
+ }
+
+ node->blink = temp;
+ temp->flink = node;
+ }
+
+ /* clear ignore */
+
+ temp = head;
+ while (temp)
+ {
+ temp->ignore = false;
+ temp = temp->flink;
+ }
+
+ /* restrip */
+
+ temp = head;
+ while (temp)
+ {
+ (void)ftpd_pathignore(temp);
+ temp = temp->flink;
+ }
+
+ return head;
+}
+
+/****************************************************************************
+ * Name: ftpd_getpath
+ ****************************************************************************/
+
+static int ftpd_getpath(FAR struct ftpd_session_s *session,
+ FAR const char *path, FAR char **abspath,
+ FAR char **workpath)
+{
+ FAR struct ftpd_pathnode_s *abspath_node;
+ FAR struct ftpd_pathnode_s *worknode;
+ FAR struct ftpd_pathnode_s *appendnode;
+ FAR char *abspath_local;
+ FAR char *workpath_local;
+
+ if (abspath)
+ {
+ *abspath = NULL;
+ }
+
+ if (workpath)
+ {
+ *workpath = NULL;
+ }
+
+ worknode = ftpd_path2node(!session->work ? "" : session->work);
+ if (!worknode)
+ {
+ return -ENOMEM;
+ }
+
+ appendnode = ftpd_path2node(path);
+ worknode = ftpd_nodeappend(worknode, appendnode, true);
+ workpath_local = ftpd_node2path(worknode, 1);
+
+ if (!workpath_local)
+ {
+ ftpd_nodefree(worknode);
+ return -ENOMEM;
+ }
+
+ abspath_node = ftpd_path2node(!session->home ? "" : session->home);
+ if (!abspath_node)
+ {
+ free(workpath_local);
+ ftpd_nodefree(worknode);
+ return -ENOMEM;
+ }
+
+ appendnode = ftpd_path2node(workpath_local);
+ abspath_node = ftpd_nodeappend(abspath_node, appendnode, false);
+ abspath_local = ftpd_node2path(abspath_node, 1);
+
+ if (!abspath_local)
+ {
+ free(workpath_local);
+ ftpd_nodefree(abspath_node);
+ ftpd_nodefree(worknode);
+ return -ENOMEM;
+ }
+
+ if (!workpath)
+ {
+ free(workpath_local);
+ }
+ else
+ {
+ *workpath = workpath_local;
+ }
+
+ if (!abspath)
+ {
+ free(abspath_local);
+ }
+ else
+ {
+ *abspath = abspath_local;
+ }
+
+ ftpd_nodefree(abspath_node);
+ ftpd_nodefree(worknode);
+ return OK;
+}
+
+/****************************************************************************
+ * Command Helpers
+ ****************************************************************************/
+/****************************************************************************
+ * Name: ftpd_changedir
+ ****************************************************************************/
+
+static int ftpd_changedir(FAR struct ftpd_session_s *session,
+ FAR const char *rempath)
+{
+ FAR char *abspath;
+ FAR char *workpath;
+ struct stat st;
+ int ret;
+
+ ret = ftpd_getpath(session, rempath, (char **)(&abspath), (char **)(&workpath));
+ if (ret < 0)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ',
+ "Can not change directory !");
+ }
+
+ ret = stat(abspath, &st);
+ if (ret < 0)
+ {
+ free(workpath);
+ free(abspath);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', rempath,
+ ": No such file or directory");
+ }
+
+ if (S_ISDIR(st.st_mode) == 0)
+ {
+ free(workpath);
+ free(abspath);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', rempath,
+ ": No such file or directory");
+ }
+
+ free(abspath);
+ if (session->work)
+ {
+ free(session->work);
+ }
+ session->work = workpath;
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 250, ' ', "CWD command successful");
+}
+
+/****************************************************************************
+ * Name: ftpd_offsatoi
+ ****************************************************************************/
+
+static off_t ftpd_offsatoi(FAR const char *filename, off_t offset)
+{
+ off_t ret;
+ off_t temp;
+ FILE *outstream;
+ int ch;
+
+ outstream = fopen(filename, "r");
+ if (!outstream)
+ {
+ int errval = errno;
+ ndbg("Failed to open %s: %d\n", filename, errval);
+ return -errval;
+ }
+
+ ret = 0;
+ temp = 0;
+
+ if (offset == (off_t)(-1))
+ {
+ for (;;)
+ {
+ ch = getc(outstream);
+ if (ch == EOF)
+ {
+ break;
+ }
+ ret++;
+ if (ch == '\n')
+ {
+ ret++;
+ }
+ }
+ /* ret is ascii mode size */
+ }
+ else
+ {
+ while (offset < temp)
+ {
+ ch = getc(outstream);
+ if (ch == EOF)
+ {
+ ret = -errno;
+ break;
+ }
+
+ ret++;
+ temp++;
+
+ if (ch == '\n')
+ {
+ temp++;
+ }
+ }
+
+ /* ret is binary mode offset */
+ }
+
+ (void)fclose(outstream);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_stream
+ ****************************************************************************/
+
+static int ftpd_stream(FAR struct ftpd_session_s *session, int cmdtype)
+{
+ FAR char *abspath;
+ FAR char *path;
+ bool isnew;
+ int oflags;
+ FAR char *buffer;
+ size_t buflen;
+ size_t wantsize;
+ ssize_t rdbytes;
+ ssize_t wrbytes;
+ off_t pos = 0;
+ int errval = 0;
+ int ret;
+
+ ret = ftpd_getpath(session, session->param, &abspath, NULL);
+ if (ret < 0)
+ {
+ ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Stream error !");
+ goto errout;
+ }
+ path = abspath;
+
+ ret = ftpd_dataopen(session);
+ if (ret < 0)
+ {
+ goto errout_with_path;
+ }
+
+ switch (cmdtype)
+ {
+ case 0: /* retr */
+ oflags = O_RDONLY;
+ break;
+
+ case 1: /* stor */
+ oflags = O_CREAT | O_WRONLY;
+ break;
+
+ case 2: /* appe */
+ oflags = O_CREAT | O_WRONLY | O_APPEND;
+ break;
+
+ default:
+ oflags = O_RDONLY;
+ break;
+ }
+
+#if defined(O_LARGEFILE)
+ oflags |= O_LARGEFILE;
+#endif
+#if defined(O_BINARY)
+ oflags |= O_BINARY;
+#endif
+
+ /* Are we creating the file? */
+
+ if ((oflags & O_CREAT) != 0)
+ {
+ int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+
+ if (session->restartpos <= 0)
+ {
+ oflags |= O_TRUNC;
+ }
+
+ isnew = true;
+ session->fd = open(path, oflags | O_EXCL, mode);
+ if (session->fd < 0)
+ {
+ isnew = false;
+ session->fd = open(path, oflags, mode);
+ }
+ }
+ else
+ {
+ /* No.. we are opening an existing file */
+
+ isnew = false;
+ session->fd = open(path, oflags);
+ }
+
+ if (session->fd < 0)
+ {
+ ret = -errno;
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Can not open file !");
+ goto errout_with_data;
+ }
+
+ /* Restart position */
+
+ if (session->restartpos > 0)
+ {
+ off_t seekoffs = (off_t)-1;
+ off_t seekpos;
+
+ /* Get the seek position */
+
+ if (session->type == FTPD_SESSIONTYPE_A)
+ {
+ seekpos = ftpd_offsatoi(path, session->restartpos);
+ if (seekpos < 0)
+ {
+ ndbg("ftpd_offsatoi failed: %d\n", seekpos);
+ errval = -seekpos;
+ }
+ }
+ else
+ {
+ seekpos = session->restartpos;
+ if (seekpos < 0)
+ {
+ ndbg("Bad restartpos: %d\n", seekpos);
+ errval = EINVAL;
+ }
+ }
+
+ /* Seek to the request position */
+
+ if (seekpos >= 0)
+ {
+ seekoffs = lseek(session->fd, seekpos, SEEK_SET);
+ if (seekoffs < 0)
+ {
+ errval = errno;
+ ndbg("lseek failed: %d\n", errval);
+ }
+ }
+
+ /* Report errors. If an error occurred, seekoffs will be negative and
+ * errval will hold the (positive) error code.
+ */
+
+ if (seekoffs < 0)
+ {
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Can not seek file !");
+ ret = -errval;
+ goto errout_with_session;
+ }
+
+ pos += (off_t)seekoffs;
+ }
+
+ /* Send success message */
+
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 150, ' ', "Opening data connection");
+ if (ret < 0)
+ {
+ ndbg("ftpd_response failed: %d\n", ret);
+ goto errout_with_session;
+ }
+
+ for (;;)
+ {
+ /* Read from the source (file or TCP connection) */
+
+ if (session->type == FTPD_SESSIONTYPE_A)
+ {
+ buffer = &session->data.buffer[session->data.buflen >> 2];
+ wantsize = session->data.buflen >> 2;
+ }
+ else
+ {
+ buffer = session->data.buffer;
+ wantsize = session->data.buflen;
+ }
+
+ if (cmdtype == 0)
+ {
+ /* Read from the file. Read returns the error condition via errno. */
+
+ rdbytes = read(session->fd, session->data.buffer, wantsize);
+ if (rdbytes < 0)
+ {
+ errval = errno;
+ }
+ }
+ else
+ {
+ /* Read from the TCP connection, ftpd_recve returns the negated error
+ * condition.
+ */
+
+ rdbytes = ftpd_recv(session->data.sd, session->data.buffer,
+ wantsize, session->rxtimeout);
+ if (rdbytes < 0)
+ {
+ errval = -rdbytes;
+ }
+ }
+
+ /* A negative vaule of rdbytes indicates a read error. errval has the
+ * (positive) error code associated with the failure.
+ */
+
+ if (rdbytes < 0)
+ {
+ ndbg("Read failed: rdbytes=%d errval=%d\n", rdbytes, errval);
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Data read error !");
+ ret = -errval;
+ break;
+ }
+
+ /* A value of rdbytes == 0 means that we have read the entire source
+ * stream.
+ */
+
+ if (rdbytes == 0)
+ {
+ /* End-of-file */
+
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 226, ' ', "Transfer complete");
+
+ /* Return success */
+
+ ret = 0;
+ break;
+ }
+
+ /* Write to the destination (file or TCP connection) */
+
+ if (session->type == FTPD_SESSIONTYPE_A)
+ {
+ /* Change to ascii */
+
+ size_t offset = 0;
+ buflen = 0;
+ while (offset < ((size_t)rdbytes))
+ {
+ if (session->data.buffer[offset] == '\n')
+ {
+ buffer[buflen++] = '\r';
+ }
+ buffer[buflen++] = session->data.buffer[offset++];
+ }
+ }
+ else
+ {
+ buffer = session->data.buffer;
+ buflen = (size_t)rdbytes;
+ }
+
+ if (cmdtype == 0)
+ {
+ /* Write to the TCP connection */
+
+ wrbytes = ftpd_send(session->data.sd, buffer, buflen, session->txtimeout);
+ if (wrbytes < 0)
+ {
+ errval = -wrbytes;
+ ndbg("ftpd_send failed: %d\n", errval);
+ }
+ }
+ else
+ {
+ /* Write to the file */
+
+ wrbytes = write(session->fd, buffer, buflen);
+ if (wrbytes < 0)
+ {
+ errval = errno;
+ ndbg("write() failed: %d\n", errval);
+ }
+ }
+
+ /* If the number of bytes returned by the write is not equal to the
+ * number that we wanted to write, then an error (or at least an
+ * unhandled condition) has occurred. errval should should hold
+ * the (positive) error code.
+ */
+
+ if (wrbytes != ((ssize_t)buflen))
+ {
+ ndbg("Write failed: wrbytes=%d errval=%d\n", wrbytes, errval);
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Data send error !");
+ ret = -errval;
+ break;
+ }
+
+ /* Get the next file offset */
+
+ pos += (off_t)wrbytes;
+ }
+
+errout_with_session:;
+ close(session->fd);
+ session->fd = -1;
+
+ if (isnew && ret < 0)
+ {
+ (void)unlink(path);
+ }
+
+errout_with_data:;
+ (void)ftpd_dataclose(session);
+
+errout_with_path:
+ free(abspath);
+
+errout:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_listoption
+ ****************************************************************************/
+
+static uint8_t ftpd_listoption(FAR char **param)
+{
+ FAR char *ptr = *param;
+ uint8_t ret = 0;
+
+ while (*ptr == '-')
+ {
+ while (*ptr != '\0' && !isspace(*ptr))
+ {
+ switch (*ptr)
+ {
+ case 'a':
+ case 'A':
+ ret |= FTPD_LISTOPTION_A;
+ break;
+
+ case 'l':
+ case 'L':
+ ret |= FTPD_LISTOPTION_L;
+ break;
+
+ case 'f':
+ case 'F':
+ ret |= FTPD_LISTOPTION_F;
+ break;
+
+ case 'r':
+ case 'R':
+ ret |= FTPD_LISTOPTION_R;
+ break;
+
+ default:
+ ret |= FTPD_LISTOPTION_UNKNOWN;
+ break;
+ }
+
+ ptr++;
+ }
+
+ if (*ptr != '\0')
+ {
+ while (*ptr != '\0' && isspace(*ptr))
+ {
+ ptr++;
+ }
+ }
+ }
+
+ *param = ptr;
+ return ret;
+}
+
+/****************************************************************************
+ * Name: fptd_listscan
+ ****************************************************************************/
+
+static int ftpd_listbuffer(FAR struct ftpd_session_s *session, FAR char *path,
+ FAR struct stat *st, FAR char *buffer,
+ size_t buflen, unsigned int opton)
+{
+ FAR char *name;
+ size_t offset = 0;
+
+ name = basename(path);
+
+ if ((opton & FTPD_LISTOPTION_L) != 0)
+ {
+ FAR const char *str;
+ struct tm tm;
+ time_t now;
+
+ if (S_ISREG(st->st_mode) != 0)
+ {
+ str = "-";
+ }
+ else if (S_ISDIR(st->st_mode) != 0)
+ {
+ str = "d";
+ }
+ else if (S_ISCHR(st->st_mode) != 0)
+ {
+ str = "c";
+ }
+ else if (S_ISBLK(st->st_mode) != 0)
+ {
+ str = "b";
+ }
+ else if (S_ISFIFO(st->st_mode) != 0)
+ {
+ str = "p";
+ }
+ else if (S_ISLNK(st->st_mode) != 0)
+ {
+ str = "l";
+ }
+ else if (S_ISSOCK(st->st_mode) != 0)
+ {
+ str = "s";
+ }
+ else
+ {
+ str = "-";
+ }
+
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+ /* User */
+
+ str = ((st->st_mode & S_IRUSR) != 0) ? "r" : "-";
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+ str = ((st->st_mode & S_IWUSR) != 0) ? "w" : "-";
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+ if ((st->st_mode & S_ISUID) != 0 && (st->st_mode & S_IXUSR) != 0)
+ {
+ str = "s";
+ }
+ else if ((st->st_mode & S_ISUID) != 0)
+ {
+ str = "S";
+ }
+ else if ((st->st_mode & S_IXUSR) != 0)
+ {
+ str = "x";
+ }
+ else
+ {
+ str = "-";
+ }
+
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+ /* group */
+
+ str = ((st->st_mode & S_IRGRP) != 0) ? "r" : "-";
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+ str = ((st->st_mode & S_IWGRP) != 0) ? "w" : "-";
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+ if ((st->st_mode & S_ISGID) != 0 && (st->st_mode & S_IXGRP) != 0)
+ {
+ str = "s";
+ }
+ else if ((st->st_mode & S_ISGID) != 0)
+ {
+ str = "S";
+ }
+ else if ((st->st_mode & S_IXGRP) != 0)
+ {
+ str = "x";
+ }
+ else
+ {
+ str = "-";
+ }
+
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+ /* other */
+
+ str = ((st->st_mode & S_IROTH) != 0) ? "r" : "-";
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+ str = ((st->st_mode & S_IWOTH) != 0) ? "w" : "-";
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+ if ((st->st_mode & S_ISVTX) != 0 && (st->st_mode & S_IXOTH) != 0)
+ {
+ str = "t";
+ }
+ else if ((st->st_mode & S_ISVTX) != 0)
+ {
+ str = "T";
+ }
+ else if ((st->st_mode & S_IXOTH) != 0)
+ {
+ str = "x";
+ }
+ else
+ {
+ str = "-";
+ }
+
+ offset += snprintf(&buffer[offset], buflen - offset, "%s", str);
+
+#ifdef __NUTTX__
+ /* Fake nlink, user id, and group id */
+
+ offset += snprintf(&buffer[offset], buflen - offset, "%4u %8u %8u", 1, 1001, 512);
+#else
+ /* nlink */
+
+ offset += snprintf(&buffer[offset], buflen - offset, "%4u", st->st_nlink);
+
+ /* user id */
+
+ offset += snprintf(&buffer[offset], buflen - offset, " %8u", st->st_uid);
+
+ /* group id */
+
+ offset += snprintf(&buffer[offset], buflen - offset, " %8u", st->st_gid);
+#endif
+
+ /* size */
+
+ offset += snprintf(&buffer[offset], buflen - offset, " %8u", st->st_size);
+
+ /* time */
+
+ memcpy(&tm, localtime((FAR const time_t *)&st->st_mtime), sizeof(tm));
+ offset += snprintf(&buffer[offset], buflen - offset, " %s %2u",
+ g_monthtab[tm.tm_mon], tm.tm_mday);
+ now = time(0);
+ if ((now - st->st_mtime) > (time_t)(60 * 60 * 24 * 180))
+ {
+ offset += snprintf(&buffer[offset], buflen - offset, " %5u",
+ tm.tm_year + 1900);
+ }
+ else
+ {
+ offset += snprintf(&buffer[offset], buflen - offset, " %02u:%02u",
+ tm.tm_hour, tm.tm_min);
+ }
+
+ /* basename */
+
+ offset += snprintf(&buffer[offset], buflen - offset, " %s", name);
+
+ /* linkname */
+
+#ifndef __NUTTX__
+ if (S_ISLNK(st->st_mode) != 0)
+ {
+ FAR char *temp;
+ int namelen;
+
+ temp = (FAR char *)malloc(PATH_MAX + 1);
+ if (temp)
+ {
+ namelen = readlink(path, temp, PATH_MAX);
+ if (namelen != (-1))\
+ {
+ temp[namelen] = '\0';
+ }
+
+ offset += snprintf(&buffer[offset], buflen - offset, " -> %s", temp);
+ free(temp);
+ }
+ }
+#endif
+
+ /* end */
+
+ offset += snprintf(&buffer[offset], buflen - offset, "\r\n");
+ }
+ else
+ {
+ /* basename */
+
+ offset += snprintf(&buffer[offset], buflen - offset, "%s\r\n", name);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: fptd_listscan
+ ****************************************************************************/
+
+static int fptd_listscan(FAR struct ftpd_session_s *session, FAR char *path,
+ unsigned int opton)
+{
+ FAR char *temp;
+ DIR *dir;
+ struct dirent *entry;
+ struct stat st;
+ int ret;
+
+ ret = stat(path, &st);
+ if (ret < 0)
+ {
+ return -errno;
+ }
+
+ if (!S_ISDIR(st.st_mode))
+ {
+ ret = ftpd_listbuffer(session, path, &st, session->data.buffer,
+ session->data.buflen, opton);
+ if (ret == 0)
+ {
+ ret = ftpd_response(session->data.sd, session->txtimeout,
+ "%s", (FAR char *)session->data.buffer);
+ }
+
+ return ret;
+ }
+
+ dir = opendir(path);
+ if (!dir)
+ {
+ int errval = errno;
+ ndbg("dir() failed\n", errval);
+ return -errval;
+ }
+
+ for (;;)
+ {
+ entry = readdir(dir);
+ if (!entry)
+ {
+ break;
+ }
+
+ if (entry->d_name[0] == '.')
+ {
+ if ((opton & FTPD_LISTOPTION_A) == 0)
+ {
+ continue;
+ }
+ }
+
+ asprintf(&temp, "%s/%s", path, entry->d_name);
+ if (!temp)
+ {
+ continue;
+ }
+
+ ret = stat(temp, &st);
+ if (ret < 0)
+ {
+ free(temp);
+ continue;
+ }
+
+ ret = ftpd_listbuffer(session, temp, &st, session->data.buffer,
+ session->data.buflen, opton);
+ if (ret >= 0)
+ {
+ ret = ftpd_response(session->data.sd, session->txtimeout,
+ "%s", session->data.buffer);
+ }
+
+ free(temp);
+ if (ret < 0)
+ {
+ break;
+ }
+ }
+
+ (void)closedir(dir);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_list
+ ****************************************************************************/
+
+static int ftpd_list(FAR struct ftpd_session_s *session, unsigned int opton)
+{
+ FAR char *abspath;
+ int ret;
+
+ ret = ftpd_getpath(session, session->param, &abspath, NULL);
+ if (ret >= 0)
+ {
+ ret = fptd_listscan(session, abspath, opton);
+ free(abspath);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Command Handlers
+ ****************************************************************************/
+/****************************************************************************
+ * Name: ftpd_command_user
+ ****************************************************************************/
+
+static int ftpd_command_user(FAR struct ftpd_session_s *session)
+{
+ int ret;
+
+ /* Clear session status */
+
+ session->flags = 0;
+ session->restartpos = 0;
+
+ /* Free session strings */
+
+ if (session->user)
+ {
+ free(session->user);
+ session->user = NULL;
+ }
+
+ if (session->renamefrom)
+ {
+ free(session->renamefrom);
+ session->renamefrom = NULL;
+ }
+
+ /* Set up the new user */
+
+ session->user = strdup(session->param);
+ if (!session->user)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 451, ' ', "Memory exhausted !");
+ }
+ session->flags |= FTPD_SESSIONFLAG_USER;
+
+ /* If there is no account information, then no login is required. */
+
+ if (!session->head)
+ {
+ FAR char *home;
+
+ home = getenv("HOME");
+ session->curr = NULL;
+ session->home = strdup(!home ? "/" : home);
+ session->work = strdup("/");
+
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 230, ' ', "Login successful.");
+ if (ret < 0)
+ {
+ session->curr = NULL;
+ }
+ return ret;
+ }
+
+ /* Try to login with no password. This willwork if no password is
+ * required for the account.
+ */
+
+ session->curr = ftpd_account_login(session, session->param, NULL);
+ if (session->curr)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 230, ' ', "Login successful.");
+ if (ret < 0)
+ {
+ session->curr = NULL;
+ }
+ return ret;
+ }
+
+ /* A password is required */
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 331, ' ', "Password required for ",
+ session->user);
+}
+
+/****************************************************************************
+ * Name: ftpd_command_pass
+ ****************************************************************************/
+
+static int ftpd_command_pass(FAR struct ftpd_session_s *session)
+{
+ int ret;
+
+ if (!session->user)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 530, ' ', "Please login with USER !");
+ }
+
+ session->curr = ftpd_account_login(session, session->user, session->param);
+ if (session->curr)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 230, ' ', "Login successful.");
+ if (ret < 0)
+ {
+ session->curr = NULL;
+ }
+ return ret;
+ }
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 530, ' ', "Login incorrect !");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_syst
+ ****************************************************************************/
+
+static int ftpd_command_syst(FAR struct ftpd_session_s *session)
+{
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 215, ' ', "UNIX Type: L8");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_type
+ ****************************************************************************/
+
+static int ftpd_command_type(FAR struct ftpd_session_s *session)
+{
+ size_t parmlen = strlen(session->param);
+
+ if (parmlen == 1)
+ {
+ switch (toupper(session->param[0]))
+ {
+ case 'A':
+ {
+ session->type = FTPD_SESSIONTYPE_A;
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 200, ' ', "Type set to A");
+ }
+
+ case 'I':
+ {
+ session->type = FTPD_SESSIONTYPE_I;
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 200, ' ', "Type set to I");
+ }
+
+ case 'L':
+ {
+ session->type = FTPD_SESSIONTYPE_L8;
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 200, ' ',
+ "Type set to L (byte size 8)");
+ }
+
+ default:
+ {
+ session->type = FTPD_SESSIONTYPE_NONE;
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 501, ' ', "Type unknown !");
+ }
+ }
+ }
+ else if (parmlen == 3)
+ {
+ if (toupper(session->param[0]) == 'L' && session->param[1] == ' ')
+ {
+ if (session->param[2] == '8')
+ {
+ session->type = FTPD_SESSIONTYPE_L8;
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 200, ' ', "Type set to L 8");
+ }
+ else
+ {
+ session->type = FTPD_SESSIONTYPE_NONE;
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 504, ' ', "Byte size must be 8 !");
+ }
+ }
+ }
+
+ session->type = FTPD_SESSIONTYPE_NONE;
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 500, ' ', "TYPE not understood !");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_mode
+ ****************************************************************************/
+
+static int ftpd_command_mode(FAR struct ftpd_session_s *session)
+{
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 502, ' ',
+ "MODE command not implemented !");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_abor
+ ****************************************************************************/
+
+static int ftpd_command_abor(FAR struct ftpd_session_s *session)
+{
+ (void)ftpd_dataclose(session);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 426, ' ',
+ "Transfer aborted. Data connection closed.");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_quit
+ ****************************************************************************/
+
+static int ftpd_command_quit(FAR struct ftpd_session_s *session)
+{
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 221, ' ', "Good-bye");
+
+ /* Return a negative value to force the server to disconnect */
+
+ return -1;
+}
+
+/****************************************************************************
+ * Name: ftpd_command_noop
+ ****************************************************************************/
+
+static int ftpd_command_noop(FAR struct ftpd_session_s *session)
+{
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 200, ' ',
+ "NOOP command successful");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_port
+ ****************************************************************************/
+
+static int ftpd_command_port(FAR struct ftpd_session_s *session)
+{
+ uint8_t value[6];
+ unsigned int utemp;
+ int temp;
+ FAR char *str;
+ int index;
+ int ret;
+
+ index = 0;
+ while (index < 6)
+ {
+ /* Get the next value from the comma-delimited string */
+
+ str = ftpd_strtok(true, ",", &session->param);
+ if (*str == '\0')
+ {
+ break;
+ }
+
+ /* ftpd_strtok differs from the real strtok in that it does not NUL-
+ * terminate the strings.
+ */
+
+ if (session->param[0] != '\0')
+ {
+ session->param[0] = '\0';
+ session->param++;
+ }
+
+ /* Get the next value from the list */
+
+ temp = atoi(str);
+ if (temp < 0 || temp > 255)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 501, ' ',
+ "Illegal PORT command");
+ if (ret < 0)
+ {
+ ndbg("ftpd_response failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ value[index++] = (uint8_t)temp;
+ }
+
+ if (index < 6)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 501, ' ', "Illegal PORT command");
+ }
+
+ (void)ftpd_dataclose(session);
+
+#if 1 /* Follow param */
+
+ memset(&session->data.addr, 0, sizeof(session->data.addr));
+
+ session->data.addr.in4.sin_family = AF_INET;
+
+ utemp = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | (value[3]);
+ session->data.addr.in4.sin_addr.s_addr = htonl((long)utemp);
+
+ utemp = (value[4] << 8) | (value[5]);
+ session->data.addr.in4.sin_port = htons((short)utemp);
+
+#else /* Follow command socket address */
+
+ session->data.addrlen = sizeof(session->data.addr);
+ ret = getpeername(session->cmd.sd, (struct sockaddr *)&session->data.addr,
+ &session->data.addrlen);
+ if (ret >= 0)
+ {
+ if (session->data.addr.ss.ss_family != AF_INET)
+ {
+ memset(&session->data.addr, 0, sizeof(session->data.addr));
+
+ session->data.addr.in4.sin_family = AF_INET;
+
+ utemp = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | (value[3]);
+ session->data.addr.in4.sin_addr.s_addr = htonl(utemp);
+ }
+
+ utemp = (value[4] << 8) | (value[5]);
+ session->data.addr.in4.sin_port = htons(utemp);
+ }
+ else
+ {
+ memset(&session->data.addr, 0, sizeof(session->data.addr));
+
+ session->data.addr.in4.sin_family = AF_INET;
+
+ utemp = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | (value[3]);
+ session->data.addr.in4.sin_addr.s_addr = htonl(utemp);
+ }
+
+ utemp = (value[4] << 8) | (value[5]);
+ session->data.addr.in4.sin_port = htons(utemp);
+#endif
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 200, ' ',
+ "PORT command successful");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_eprt
+ ****************************************************************************/
+
+static int ftpd_command_eprt(FAR struct ftpd_session_s *session)
+{
+ FAR const char *str;
+ FAR char *field[3];
+ sa_family_t family;
+ size_t left;
+ size_t right;
+ int count;
+ int index;
+
+ left = 0;
+ right = strlen(session->param);
+
+ if (right <= 0)
+ {
+ /* no message ? */
+
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 502, ' ',
+ "EPRT command not implemented !");
+ return -EINVAL;
+ }
+ right--;
+
+ while (session->param[left] != '\0')
+ {
+ if (session->param[left] == '|')
+ {
+ left++;
+ break;
+ }
+ left++;
+ }
+
+ if (right <= 0 || left > right)
+ {
+ /* Invalid format */
+
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 502, ' ',
+ "EPRT command not implemented !");
+ return -EINVAL;
+ }
+
+ count = 3;
+ for (index = 0; index < count; index++)
+ {
+ field[index] = NULL;
+ }
+
+ str = (FAR const char *)&session->param[left];
+ for (index = 0; index < count && *str != '\0'; index++)
+ {
+ field[index] = ftpd_strtok_alloc(true, ",|)", &str);
+ if (!field[index])
+ {
+ break;
+ }
+
+ if (*str != '\0')
+ {
+ str++;
+ }
+ }
+
+ if (index < count)
+ {
+ for (index = 0; index < count; index++)
+ {
+ if (field[index])
+ {
+ free(field[index]);
+ }
+ }
+
+ (void)ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 502, ' ',
+ "EPRT command not implemented !");
+ return -EINVAL;
+ }
+
+ (void)ftpd_dataclose(session);
+
+ memset(&session->data.addr, 0, sizeof(session->data.addr));
+ family = atoi(field[0]);
+#ifndef CONFIG_NET_IPv6
+ if (family == 1)
+ {
+ family = AF_INET;
+
+ session->data.addr.in4.sin_family = family;
+ (void)inet_pton(family, field[1], &session->data.addr.in4.sin_addr);
+ session->data.addr.in4.sin_port = htons((short)atoi(field[2]));
+ }
+ else
+#endif
+#ifdef CONFIG_NET_IPv6
+ if (family == 2)
+ {
+ family = AF_INET6;
+
+ session->data.addr.in6.sin6_family = family;
+ (void)inet_pton(family, field[1], &session->data.addr.in6.sin6_addr);
+ session->data.addr.in6.sin6_port = htons((short)atoi(field[2]));
+ }
+ else
+#endif
+ {
+ ndbg("Unrecognized family: %d\n", family);
+ family = AF_UNSPEC;
+ }
+
+ for (index = 0;index < count;index++)
+ {
+ if (field[index])
+ {
+ free(field[index]);
+ }
+ }
+
+ if (family == AF_UNSPEC)
+ {
+ ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 502, ' ',
+ "EPRT command not implemented !");
+ return -EINVAL;
+ }
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 200, ' ', "EPRT command successful");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_pwd
+ ****************************************************************************/
+
+static int ftpd_command_pwd(FAR struct ftpd_session_s *session)
+{
+ FAR const char *workpath;
+
+ if (!session->work)
+ {
+ workpath = "";
+ }
+ else
+ {
+ workpath = session->work;
+ }
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ "%03u%c\"%s\" is current directory.\r\n",
+ 257, ' ', workpath);
+}
+
+/****************************************************************************
+ * Name: ftpd_command_cwd
+ ****************************************************************************/
+
+static int ftpd_command_cwd(FAR struct ftpd_session_s *session)
+{
+ return ftpd_changedir(session, session->param);
+}
+
+/****************************************************************************
+ * Name: ftpd_command_cdup
+ ****************************************************************************/
+
+static int ftpd_command_cdup(FAR struct ftpd_session_s *session)
+{
+ return ftpd_changedir(session, g_cdup);
+}
+
+/****************************************************************************
+ * Name: ftpd_command_rmd
+ ****************************************************************************/
+
+static int ftpd_command_rmd(FAR struct ftpd_session_s *session)
+{
+ FAR char *abspath;
+ FAR char *workpath;
+ int ret;
+
+ ret = ftpd_getpath(session, session->param, &abspath, &workpath);
+ if (ret < 0)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ',
+ "Can not remove directory !");
+ }
+
+ if (strcmp(session->home, abspath) == 0)
+ {
+ free(abspath);
+ free(workpath);
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ',
+ "Can not remove home directory !");
+ }
+
+ if (strcmp(session->work, workpath) == 0)
+ {
+ free(abspath);
+ free(workpath);
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ',
+ "Can not remove current directory !");
+ }
+
+ ret = rmdir(abspath);
+ if (ret < 0)
+ {
+ free(abspath);
+ free(workpath);
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ',
+ "Can not remove directory !");
+ }
+
+ free(abspath);
+ free(workpath);
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 250, ' ',
+ "RMD command successful");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_mkd
+ ****************************************************************************/
+
+static int ftpd_command_mkd(FAR struct ftpd_session_s *session)
+{
+ FAR char *abspath;
+ int ret;
+
+ ret = ftpd_getpath(session, session->param, &abspath, NULL);
+ if (ret < 0)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ',
+ "Can not make directory !");
+ }
+
+ ret = mkdir(abspath, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ if (ret < 0)
+ {
+ free(abspath);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Can not make directory !");
+ }
+
+ free(abspath);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 250, ' ', "MKD command successful");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_dele
+ ****************************************************************************/
+
+static int ftpd_command_dele(FAR struct ftpd_session_s *session)
+{
+ FAR char *abspath;
+ FAR char *workpath;
+ int ret;
+
+ ret = ftpd_getpath(session, session->param, &abspath, &workpath);
+ if (ret < 0)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Can not delete file !");
+ }
+
+ if (strcmp(session->home, abspath) == 0)
+ {
+ free(abspath);
+ free(workpath);
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ',
+ "Can not delete home directory !");
+ }
+
+ if (strcmp(session->work, workpath) == 0)
+ {
+ free(abspath);
+ free(workpath);
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ',
+ "Can not delete current directory !");
+ }
+
+ ret = unlink(abspath);
+ if (ret < 0)
+ {
+ free(abspath);
+ free(workpath);
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Can not delete file !");
+ }
+
+ free(abspath);
+ free(workpath);
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 250, ' ', "DELE command successful");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_pasv
+ ****************************************************************************/
+
+static int ftpd_command_pasv(FAR struct ftpd_session_s *session)
+{
+ unsigned int value[6];
+ unsigned int temp;
+ int ret;
+
+ (void)ftpd_dataclose(session);
+
+ session->data.addrlen = sizeof(session->data.addr);
+
+ session->data.sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (session->data.sd < 0)
+ {
+ (void)ftpd_dataclose(session);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 425, ' ', "PASV socket create fail !");
+ }
+
+ ret = getsockname(session->cmd.sd, (FAR struct sockaddr *)&session->data.addr,
+ &session->data.addrlen);
+ if (ret < 0)
+ {
+ (void)ftpd_dataclose(session);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 425, ' ', "PASV getsockname fail !");
+ }
+
+#ifdef CONFIG_NET_IPv6
+ if (session->data.addr.ss.ss_family == AF_INET6)
+ {
+ /* Convert ipv6 to ipv4 */
+
+ if ((IN6_IS_ADDR_V4MAPPED(&session->data.addr.in6.sin6_addr) != 0) ||
+ (IN6_IS_ADDR_V4COMPAT(&session->data.addr.in6.sin6_addr) != 0))
+ {
+ /* convert ipv6 to ipv4 */
+
+ in_addr in4addr;
+
+ in4addr.s_addr = session->data.addr.in6.sin6_addr.s6_addr32[3];
+
+ memset(&session->data.addr, 0, sizeof(session->data.addr));
+ session->data.addr.in4.sin_family = AF_INET;
+ session->data.addr.in4.sin_addr.s_addr = in4addr.s_addr;
+ }
+ }
+ else
+#endif
+#ifndef CONFIG_NET_IPv6
+ if (session->data.addr.ss.ss_family == AF_INET)
+ {
+ /* Fixed to ipv4 */
+
+ memset((FAR void *)(&session->data.addr), 0, sizeof(session->data.addr));
+ session->data.addr.in4.sin_family = AF_INET;
+ session->data.addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ else
+#endif
+ {
+ ndbg("Unsupported family\n");
+ }
+
+ session->data.addr.in4.sin_port = 0;
+ ret = bind(session->data.sd, (FAR const struct sockaddr *)&session->data.addr,
+ session->data.addrlen);
+ if (ret < 0)
+ {
+ (void)ftpd_dataclose(session);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 425, ' ', "PASV bind fail !");
+ }
+
+ ret = getsockname(session->data.sd, (FAR struct sockaddr *)&session->data.addr,
+ &session->data.addrlen);
+ if (ret < 0)
+ {
+ (void)ftpd_dataclose(session);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 425, ' ', "PASV getsockname fail !");
+ }
+
+ ret = listen(session->data.sd, 1);
+ if (ret < 0)
+ {
+ (void)ftpd_dataclose(session);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 425, ' ', "PASV listen fail !");
+ }
+
+ if (ntohl(session->data.addr.in4.sin_addr.s_addr) == INADDR_ANY)
+ {
+ (void)ftpd_dataclose(session);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 425, ' ',
+ "Can not open passive connection");
+ }
+
+ temp = ntohl(session->data.addr.in4.sin_addr.s_addr);
+ value[0] = (temp >> 24) & 0xff;
+ value[1] = (temp >> 16) & 0xff;
+ value[2] = (temp >> 8) & 0xff;
+ value[3] = (temp) & 0xff;
+
+ temp = (unsigned int)ntohs(session->data.addr.in4.sin_port);
+ value[4] = (temp >> 8) & 0xff;
+ value[5] = (temp) & 0xff;
+
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ "%03u%cEntering passive mode (%u,%u,%u,%u,%u,%u).\r\n",
+ 227, ' ',
+ value[0], value[1], value[2],
+ value[3], value[4], value[5]);
+ if (ret < 0)
+ {
+ (void)ftpd_dataclose(session);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_command_epsv
+ ****************************************************************************/
+
+static int ftpd_command_epsv(FAR struct ftpd_session_s *session)
+{
+ int ret;
+
+ (void)ftpd_dataclose(session);
+
+ session->data.addrlen = sizeof(session->data.addr);
+
+#ifdef CONFIG_NET_IPv6
+ session->data.sd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ if (session->data.sd < 0)
+ {
+ session->data.sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ }
+ else
+ {
+#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
+ int ipv6only = 0;
+ (void)setsockopt(session->data.sd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only));
+#endif
+ }
+#else
+ session->data.sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+#endif
+
+ if (session->data.sd < 0)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 500, ' ', "EPSV socket create fail !");
+ (void)ftpd_dataclose(session);
+ return ret;
+ }
+
+ ret = getsockname(session->cmd.sd, (FAR struct sockaddr *)&session->data.addr,
+ &session->data.addrlen);
+ if (ret < 0)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 500, ' ', "EPSV getsockname fail !");
+ (void)ftpd_dataclose(session);
+ return ret;
+ }
+
+#ifdef CONFIG_NET_IPv6
+ if (session->data.addr.ss.ss_family == AF_INET6)
+ {
+ session->data.addr.in6.sin6_port = htons(0);
+ }
+ else if (session->data.addr.ss.ss_family == AF_INET)
+ {
+ session->data.addr.in4.sin_port = htons(0);
+ }
+#else
+ session->data.addr.in4.sin_port = htons(0);
+#endif
+
+ ret = bind(session->data.sd, (FAR const struct sockaddr *)&session->data.addr,
+ session->data.addrlen);
+ if (ret < 0)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 500, ' ', "EPSV bind fail !");
+ (void)ftpd_dataclose(session);
+ return ret;
+ }
+
+ ret = getsockname(session->data.sd, (FAR struct sockaddr *)&session->data.addr,
+ &session->data.addrlen);
+ if (ret < 0)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 500, ' ', "EPSV getsockname fail !");
+ (void)ftpd_dataclose(session);
+ return ret;
+ }
+
+ ret = listen(session->data.sd, 1);
+ if (ret < 0)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 500, ' ', "EPSV listen fail !");
+ (void)ftpd_dataclose(session);
+ return ret;
+ }
+
+#ifdef CONFIG_NET_IPv6
+ if (session->data.addr.ss.ss_family == AF_INET6)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ "%03u%cEntering Extended Passive Mode (|||%u|).\r\n",
+ 229, ' ',
+ ntohs(session->data.addr.in6.sin6_port));
+ if (ret < 0)
+ {
+ (void)ftpd_dataclose(session);
+ return ret;
+ }
+ }
+ else
+#else
+ if (session->data.addr.ss.ss_family == AF_INET)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ "%03u%cEntering Extended Passive Mode (|%u||%u|).\r\n",
+ 229, ' ', 1,
+ ntohs(session->data.addr.in4.sin_port));
+ if (ret < 0)
+ {
+ (void)ftpd_dataclose(session);
+ return ret;
+ }
+ }
+ else
+#endif
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 502, ' ',
+ "EPSV command not implemented !");
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_command_list
+ ****************************************************************************/
+
+static int ftpd_command_list(FAR struct ftpd_session_s *session)
+{
+ uint8_t opton = FTPD_LISTOPTION_L;
+ int ret;
+
+ ret = ftpd_dataopen(session);
+ if (ret < 0)
+ {
+ return 0;
+ }
+
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 150, ' ',
+ "Opening ASCII mode data connection for file list");
+ if (ret < 0)
+ {
+ (void)ftpd_dataclose(session);
+ return ret;
+ }
+
+ opton |= ftpd_listoption((char **)(&session->param));
+ (void)ftpd_list(session, opton);
+
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 226, ' ', "Transfer complete");
+
+ (void)ftpd_dataclose(session);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_command_nlst
+ ****************************************************************************/
+
+static int ftpd_command_nlst(FAR struct ftpd_session_s *session)
+{
+ uint8_t opton = 0;
+ int ret;
+
+ ret = ftpd_dataopen(session);
+ if (ret < 0)
+ {
+ return 0;
+ }
+
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 150, ' ',
+ "Opening ASCII mode data connection for file list");
+ if (ret < 0)
+ {
+ (void)ftpd_dataclose(session);
+ return ret;
+ }
+
+ opton |= ftpd_listoption((char **)(&session->param));
+ (void)ftpd_list(session, opton);
+
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 226, ' ', "Transfer complete");
+
+ (void)ftpd_dataclose(session);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_command_acct
+ ****************************************************************************/
+
+static int ftpd_command_acct(FAR struct ftpd_session_s *session)
+{
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 502, ' ', "ACCT command not implemented !");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_size
+ ****************************************************************************/
+
+static int ftpd_command_size(FAR struct ftpd_session_s *session)
+{
+ FAR char *abspath;
+ FAR char *path;
+ struct stat st;
+ FAR FILE *outstream;
+ off_t offset;
+ int ch;
+ int status;
+ int ret;
+
+ ret = ftpd_getpath(session, session->param, &abspath, NULL);
+ if (ret < 0)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Unknown size !");
+ }
+ path = abspath;
+
+ ret = 0;
+ switch (session->type)
+ {
+ case FTPD_SESSIONTYPE_NONE:
+ case FTPD_SESSIONTYPE_L8:
+ case FTPD_SESSIONTYPE_I:
+ {
+ status = stat(path, &st);
+ if (status < 0)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', session->param,
+ ": not a regular file.");
+ }
+ else if (!S_ISREG(st.st_mode))
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', session->param,
+ ": not a regular file.");
+ }
+ else
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ "%03u%c%llu\r\n", 213, ' ', (unsigned long long)st.st_size);
+ }
+ }
+ break;
+
+ case FTPD_SESSIONTYPE_A:
+ {
+ status = stat(path, &st);
+ if (status < 0)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', session->param,
+ ": not a regular file.");
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+ else if (!S_ISREG(st.st_mode))
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', session->param,
+ ": not a regular file.");
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+
+
+ outstream = fopen(path, "r");
+ if (!outstream)
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', session->param,
+ ": Can not open file !");
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+
+ offset = 0;
+ for (;;)
+ {
+ ch = getc(outstream);
+ if (ch == EOF)
+ {
+ break;
+ }
+ else if (ch == 'c')
+ {
+ offset++;
+ }
+ offset++;
+ }
+
+ (void)fclose(outstream);
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ "%03u%c%llu\r\n", 213, ' ', (unsigned long long)offset);
+ }
+ break;
+
+ default:
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 504, ' ', "SIZE not implemented for type");
+ }
+ break;
+ }
+
+ free(abspath);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_command_stru
+ ****************************************************************************/
+
+static int ftpd_command_stru(FAR struct ftpd_session_s *session)
+{
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 502, ' ', "STRU command not implemented !");
+}
+
+/****************************************************************************
+ * Name:
+ ****************************************************************************/
+
+static int ftpd_command_rnfr(FAR struct ftpd_session_s *session)
+{
+ FAR char *abspath;
+ FAR char *path;
+ struct stat st;
+ int ret;
+
+ if (session->renamefrom)
+ {
+ free(session->renamefrom);
+ session->renamefrom = NULL;
+ }
+
+ ret = ftpd_getpath(session, session->param, &abspath, NULL);
+ if (ret < 0)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "RNFR error !");
+ }
+ path = abspath;
+
+ ret = stat(path, &st);
+ if (ret < 0)
+ {
+ free(abspath);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', session->param,
+ ": No such file or directory.");
+ }
+
+ session->renamefrom = abspath;
+ session->flags |= FTPD_SESSIONFLAG_RENAMEFROM;
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 350, ' ', "RNFR successful");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_rnto
+ ****************************************************************************/
+
+static int ftpd_command_rnto(FAR struct ftpd_session_s *session)
+{
+ FAR char *abspath;
+ int ret;
+
+ if (!session->renamefrom)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "RNTO error !");
+ }
+
+ ret = ftpd_getpath(session, session->param, &abspath, NULL);
+ if (ret < 0)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "RNTO error !");
+ }
+
+ ret = rename(session->renamefrom, abspath);
+ if (ret < 0)
+ {
+ free(abspath);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', session->param,
+ ": Rename error.");
+ }
+
+ free(abspath);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 250, ' ', "Rename successful");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_retr
+ ****************************************************************************/
+
+static int ftpd_command_retr(FAR struct ftpd_session_s *session)
+{
+ return ftpd_stream(session, 0);
+}
+
+/****************************************************************************
+ * Name: ftpd_command_stor
+ ****************************************************************************/
+
+static int ftpd_command_stor(FAR struct ftpd_session_s *session)
+{
+ return ftpd_stream(session, 1);
+}
+
+/****************************************************************************
+ * Name: ftpd_command_appe
+ ****************************************************************************/
+
+static int ftpd_command_appe(FAR struct ftpd_session_s *session)
+{
+ return ftpd_stream(session, 2);
+}
+
+/****************************************************************************
+ * Name: ftpd_command_rest
+ ****************************************************************************/
+
+static int ftpd_command_rest(FAR struct ftpd_session_s *session)
+{
+#ifdef CONFIG_HAVE_LONG_LONG
+ session->restartpos = (off_t)atoll(session->param);
+#else
+ session->restartpos = (off_t)atoi(session->param);
+#endif
+ session->flags |= FTPD_SESSIONFLAG_RESTARTPOS;
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 320, ' ', "Restart position ready");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_mdtm
+ ****************************************************************************/
+
+static int ftpd_command_mdtm(FAR struct ftpd_session_s *session)
+{
+ FAR char *abspath;
+ FAR char *path;
+ struct stat st;
+ struct tm tm;
+ int ret;
+
+ ret = ftpd_getpath(session, session->param, &abspath, NULL);
+ if (ret <0)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 550, ' ', "Unknown size !");
+ }
+ path = abspath;
+
+ ret = stat(path, &st);
+ if (ret < 0)
+ {
+ free(abspath);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', session->param,
+ ": not a plain file.");
+ }
+
+ if (!S_ISREG(st.st_mode))
+ {
+ free(abspath);
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 550, ' ', session->param,
+ ": not a plain file.");
+ }
+
+ free(abspath);
+
+ memcpy(&tm, gmtime(&st.st_mtime), sizeof(tm));
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ "%03u%c%04u%02u%02u%02u%02u%02u\r\n", 213, ' ',
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+}
+
+/****************************************************************************
+ * Name: ftpd_command_opts
+ ****************************************************************************/
+
+static int ftpd_command_opts(FAR struct ftpd_session_s *session)
+{
+ FAR char *str;
+ FAR char *option;
+ FAR char *value;
+ bool remote = false;
+ bool local = false;
+
+ /* token: name and value */
+
+ str = session->param;
+ option = ftpd_strtok(true, " \t", &str);
+
+ /* Unlike the "real" strtok, ftpd_strtok does not NUL-terminate
+ * the returned string.
+ */
+
+ if (*str != '\0')
+ {
+ *str = '\0';
+ str++;
+ }
+ value = str;
+
+ if (strcasecmp(option, "UTF8") == 0 || strcasecmp(option, "UTF-8") == 0)
+ {
+ FAR char *lang;
+
+ if (value[0] == '\0' || strcasecmp(value, "ON") == 0 ||
+ strcasecmp(value, "ENABLE") == 0 || strcasecmp(value, "TRUE") == 0)
+ {
+ remote = true;
+ }
+ else {
+ remote = false;
+ }
+
+ lang = getenv("LANG");
+ if (lang)
+ {
+ if (strcasestr(lang, "UTF8") || strcasestr(lang, "UTF-8"))
+ {
+ local = true;
+ }
+ else
+ {
+ local = false;
+ }
+ }
+#if 1 /* OPTION: UTF-8 is default */
+ else
+ {
+ local = true;
+ }
+#endif
+
+ if (remote != local)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 504, ' ', "UIF-8 disabled");
+ }
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 200, ' ', "OK, UTF-8 enabled");
+ }
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ "%03u%c%s%s%s\r\n", 501, ' ', "OPTS: ", option,
+ " not understood");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_site
+ ****************************************************************************/
+
+static int ftpd_command_site(FAR struct ftpd_session_s *session)
+{
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 502, ' ', "SITE command not implemented !");
+}
+
+/****************************************************************************
+ * Name: ftpd_command_help
+ ****************************************************************************/
+
+static int ftpd_command_help(FAR struct ftpd_session_s *session)
+{
+ int index;
+ int ret;
+
+ index = 0;
+ while (g_ftpdhelp[index])
+ {
+ if (index == 0 || !g_ftpdhelp[index + 1])
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 214,
+ !g_ftpdhelp[index + 1] ? ' ' : '-',
+ g_ftpdhelp[index]);
+ }
+ else
+ {
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ "%c%s\r\n", ' ', g_ftpdhelp[index]);
+ }
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ index++;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ftpd_command
+ ****************************************************************************/
+
+static int ftpd_command(FAR struct ftpd_session_s *session)
+{
+ int index = 0;
+
+ /* Search the command table for a matching command */
+
+ for (index = 0; g_ftpdcmdtab[index].command; index++)
+ {
+ /* Does the command string match this entry? */
+
+ if (strcmp(session->command, g_ftpdcmdtab[index].command) == 0)
+ {
+ /* Yes.. is a login required to execute this command? */
+
+ if ((g_ftpdcmdtab[index].flags & FTPD_CMDFLAG_LOGIN) != 0)
+ {
+ /* Yes... Check if the user is logged in */
+
+ if (!session->curr && session->head)
+ {
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 530, ' ',
+ "Please login with USER and PASS !");
+ }
+ }
+
+ /* Check if there is a handler for the command */
+
+ if (g_ftpdcmdtab[index].handler)
+ {
+ /* Yess.. invoke the command handler. */
+
+ return g_ftpdcmdtab[index].handler(session);
+ }
+
+ /* No... this command is not in the command table. Break out of
+ * the loop and send the 500 message.
+ */
+
+ break;
+ }
+ }
+
+ /* There is nothing in the command table matching this command */
+
+ return ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt2, 500, ' ', session->command,
+ " not understood");
+}
+
+/****************************************************************************
+ * Worker Thread
+ ****************************************************************************/
+/****************************************************************************
+ * Name: ftpd_startworker
+ ****************************************************************************/
+
+static int ftpd_startworker(pthread_startroutine_t handler, FAR void *arg,
+ size_t stacksize)
+{
+ pthread_t threadid;
+ pthread_attr_t attr;
+ int ret;
+
+ /* Initialize the thread attributes */
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0)
+ {
+ ndbg("pthread_attr_init() failed: %d\n", ret);
+ goto errout;
+ }
+
+ /* The set the thread stack size */
+
+ ret = pthread_attr_setstacksize(&attr, stacksize);
+ if (ret != 0)
+ {
+ ndbg("pthread_attr_setstacksize() failed: %d\n", ret);
+ goto errout_with_attr;
+ }
+
+ /* And create the thread */
+
+ ret = pthread_create(&threadid, &attr, handler, arg);
+ if (ret != 0)
+ {
+ ndbg("pthread_create() failed: %d\n", ret);
+ goto errout_with_attr;
+ }
+
+ /* Put the thread in the detached stated */
+
+ ret = pthread_detach(threadid);
+ if (ret != 0)
+ {
+ ndbg("pthread_detach() failed: %d\n", ret);
+ }
+
+errout_with_attr:
+ pthread_attr_destroy(&attr);
+errout:
+ return -ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_freesession
+ ****************************************************************************/
+
+static void ftpd_freesession(FAR struct ftpd_session_s *session)
+{
+ /* Free resources */
+
+ if (session->renamefrom)
+ {
+ free(session->renamefrom);
+ }
+
+ if (session->work)
+ {
+ free(session->work);
+ }
+
+ if (session->home)
+ {
+ free(session->home);
+ }
+
+ if (session->user)
+ {
+ free(session->user);
+ }
+
+ if (session->fd < 0)
+ {
+ close(session->fd);
+ }
+
+ if (session->data.buffer)
+ {
+ free(session->data.buffer);
+ }
+
+ (void)ftpd_dataclose(session);
+
+ if (session->cmd.buffer)
+ {
+ free(session->cmd.buffer);
+ }
+
+ if (session->cmd.sd <0)
+ {
+ close(session->cmd.sd);
+ }
+
+ free(session);
+}
+
+/****************************************************************************
+ * Name: ftpd_workersetup
+ ****************************************************************************/
+
+static void ftpd_workersetup(FAR struct ftpd_session_s *session)
+{
+#if defined(CONFIG_NET_HAVE_IPTOS) || defined(CONFIG_NET_HAVE_OOBINLINE)
+ int temp;
+#endif
+#ifdef CONFIG_NET_HAVE_SOLINGER
+ struct linger ling;
+#endif
+
+#ifdef CONFIG_NET_HAVE_IPTOS
+ temp = IPTOS_LOWDELAY;
+ (void)setsockopt(session->cmd.sd, IPPROTO_IP, IP_TOS, &temp, sizeof(temp));
+#endif
+
+#ifdef CONFIG_NET_HAVE_OOBINLINE
+ temp = 1;
+ (void)setsockopt(session->cmd.sd, SOL_SOCKET, SO_OOBINLINE, &temp, sizeof(temp));
+#endif
+
+#ifdef CONFIG_NET_HAVE_SOLINGER
+ (void)memset(&ling, 0, sizeof(ling));
+ ling.l_onoff = 1;
+ ling.l_linger = 4;
+ (void)setsockopt(session->cmd.sd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
+#endif
+}
+
+/****************************************************************************
+ * Name: ftpd_worker
+ ****************************************************************************/
+
+static FAR void *ftpd_worker(FAR void *arg)
+{
+ FAR struct ftpd_session_s *session = (FAR struct ftpd_session_s *)arg;
+ ssize_t recvbytes;
+ size_t offset;
+ uint8_t ch;
+ int ret;
+
+ nvdbg("Worker started\n");
+ DEBUGASSERT(session);
+
+ /* Configure the session sockets */
+
+ ftpd_workersetup(session);
+
+ /* Send the welcoming message */
+
+ ret = ftpd_response(session->cmd.sd, session->txtimeout,
+ g_respfmt1, 220, ' ', CONFIG_FTPD_SERVERID);
+ if (ret < 0)
+ {
+ ndbg("ftpd_response() failed: %d\n", ret);
+ ftpd_freesession(session);
+ return NULL;
+ }
+
+ /* Then loop processing FTP commands */
+
+ for (;;)
+ {
+ /* Receive the next command */
+
+ recvbytes = ftpd_recv(session->cmd.sd, session->cmd.buffer,
+ session->cmd.buflen - 1, session->rxtimeout);
+
+ /* recbytes < 0 is a receive failure (posibily a timeout);
+ * recbytes == 0 indicates that we have lost the connection.
+ */
+
+ if (recvbytes <= 0)
+ {
+ /* Break out of the server loop */
+
+ break;
+ }
+
+ /* Make sure that the recevied string is NUL terminated */
+
+ session->cmd.buffer[recvbytes] = '\0';
+
+ /* TELNET protocol (RFC854)
+ * IAC 255(FFH) interpret as command:
+ * IP 244(F4H) interrupt process--permanently
+ * DM 242(F2H) data mark--for connect. cleaning
+ */
+
+ offset = 0;
+ while (recvbytes > 0)
+ {
+ ch = session->cmd.buffer[offset];
+ if (ch != 0xff && ch != 0xf4 && ch != 0xf2)
+ {
+ break;
+ }
+
+ (void)ftpd_send(session->cmd.sd, &session->cmd.buffer[offset], 1, session->txtimeout);
+
+ offset++;
+ recvbytes--;
+ }
+
+ /* Just continue if there was nothing of interest in the packet */
+
+ if (recvbytes <= 0)
+ {
+ continue;
+ }
+
+ /* Make command message */
+
+ session->command = &session->cmd.buffer[offset];
+ while (session->cmd.buffer[offset] != '\0')
+ {
+ if (session->cmd.buffer[offset] == '\r' &&
+ session->cmd.buffer[offset + ((ssize_t)1)] == '\n')
+ {
+ session->cmd.buffer[offset] = '\0';
+ break;
+ }
+ offset++;
+ }
+
+ /* Parse command and param tokens */
+
+ session->param = session->command;
+ session->command = ftpd_strtok(true, " \t", &session->param);
+
+ /* Unlike the "real" strtok, ftpd_strtok does not NUL-terminate
+ * the returned string.
+ */
+
+ if (session->param[0] != '\0')
+ {
+ session->param[0] = '\0';
+ session->param++;
+ }
+
+ /* Dispatch the FTP command */
+
+ ret = ftpd_command(session);
+ if (ret < 0)
+ {
+ ndbg("Disconnected by the command handler: %d\n", ret);
+ break;
+ }
+ }
+
+ ftpd_freesession(session);
+ return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ftpd_open
+ *
+ * Description:
+ * Create an instance of the FTPD server and return a handle that can be
+ * used to run the server.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * On success, a non-NULL handle is returned that can be used to reference
+ * the server instance.
+ *
+ ****************************************************************************/
+
+FTPD_SESSION ftpd_open(void)
+{
+ FAR struct ftpd_server_s *server;
+
+ server = ftpd_openserver(21);
+ if (!server)
+ {
+ server = ftpd_openserver(2211);
+ }
+
+ return (FTPD_SESSION)server;
+}
+
+/****************************************************************************
+ * Name: ftpd_adduser
+ *
+ * Description:
+ * Add one FTP user.
+ *
+ * Input Parameters:
+ * handle - A handle previously returned by ftpd_open
+ * accountflags - The characteristics of this user (see FTPD_ACCOUNTFLAGS_*
+ * definitions).
+ * user - The user login name. May be NULL indicating that no login is
+ * required.
+ * passwd - The user password. May be NULL indicating that no password
+ * is required.
+ * home - The user home directory. May be NULL.
+ *
+ * Returned Value:
+ * Zero is returned on success. A negated errno value is return on
+ * failure.
+ *
+ ****************************************************************************/
+
+int ftpd_adduser(FTPD_SESSION handle, uint8_t accountflags,
+ FAR const char *user, FAR const char *passwd,
+ FAR const char *home)
+{
+ FAR struct ftpd_server_s *server;
+ FAR struct ftpd_account_s *newaccount;
+ int ret;
+
+ DEBUGASSERT(handle);
+
+ newaccount = ftpd_account_new(user, accountflags);
+ if (!newaccount)
+ {
+ ndbg("Failed to allocte memory to the account\n");
+ ret = -ENOMEM;
+ goto errout;
+ }
+
+ ret = ftpd_account_setpassword(newaccount, passwd);
+ if (ret < 0)
+ {
+ ndbg("ftpd_account_setpassword failed: %d\n", ret);
+ goto errout_with_account;
+ }
+
+ ret = ftpd_account_sethome(newaccount, home);
+ if (ret < 0)
+ {
+ ndbg("ftpd_account_sethome failed: %d\n", ret);
+ goto errout_with_account;
+ }
+
+ server = (FAR struct ftpd_server_s *)handle;
+ ret = ftpd_account_add(server, newaccount);
+ if (ret < 0)
+ {
+ ndbg("ftpd_account_add failed: %d\n", ret);
+ goto errout_with_account;
+ }
+
+ return OK;
+
+errout_with_account:
+ ftpd_account_free(newaccount);
+
+errout:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_session
+ *
+ * Description:
+ * Execute the FTPD server. This thread does not return until either (1)
+ * the timeout expires with no connection, (2) some other error occurs, or
+ * (2) a connection was accepted and an FTP worker thread was started to
+ * service the session.
+ *
+ * Input Parameters:
+ * handle - A handle previously returned by ftpd_open
+ * timeout - A time in milliseconds to wait for a connection. If this
+ * time elapses with no connected, the -ETIMEDOUT error will be returned.
+ *
+ * Returned Value:
+ * Zero is returned if the FTP worker was started. On failure, a negated
+ * errno value is returned to indicate why the servier terminated.
+ * -ETIMEDOUT indicates that the user-provided timeout elapsed with no
+ * connection.
+ *
+ ****************************************************************************/
+
+int ftpd_session(FTPD_SESSION handle, int timeout)
+{
+ FAR struct ftpd_server_s *server;
+ FAR struct ftpd_session_s *session;
+ int ret;
+
+ DEBUGASSERT(handle);
+
+ server = (FAR struct ftpd_server_s *)handle;
+
+ /* Allocate a session */
+
+ session = (FAR struct ftpd_session_s *)zalloc(sizeof(struct ftpd_session_s));
+ if (!session)
+ {
+ ndbg("Failed to allocate session\n");
+ ret = -ENOMEM;
+ goto errout;
+ }
+
+ /* Initialize the session */
+
+ session->server = server;
+ session->head = server->head;
+ session->curr = NULL;
+ session->flags = 0;
+ session->txtimeout = -1;
+ session->rxtimeout = -1;
+ session->cmd.sd = (int)(-1);
+ session->cmd.addrlen = (socklen_t)sizeof(session->cmd.addr);
+ session->cmd.buflen = (size_t)CONFIG_FTPD_CMDBUFFERSIZE;
+ session->cmd.buffer = NULL;
+ session->command = NULL;
+ session->param = NULL;
+ session->data.sd = -1;
+ session->data.addrlen = sizeof(session->data.addr);
+ session->data.buflen = CONFIG_FTPD_DATABUFFERSIZE;
+ session->data.buffer = NULL;
+ session->restartpos = 0;
+ session->fd = -1;
+ session->user = NULL;
+ session->type = FTPD_SESSIONTYPE_NONE;
+ session->home = NULL;
+ session->work = NULL;
+ session->renamefrom = NULL;
+
+ /* Allocate a command buffer */
+
+ session->cmd.buffer = (FAR char *)malloc(session->cmd.buflen);
+ if (!session->cmd.buffer)
+ {
+ ndbg("Failed to allocate command buffer\n");
+ ret = -ENOMEM;
+ goto errout_with_session;
+ }
+
+ /* Allocate a data buffer */
+
+ session->data.buffer = (FAR char *)malloc(session->data.buflen);
+ if (!session->data.buffer)
+ {
+ ndbg("Failed to allocate data buffer\n");
+ ret = -ENOMEM;
+ goto errout_with_session;
+ }
+
+ /* Accept a connection */
+
+ session->cmd.sd = ftpd_accept(server->sd, (FAR void *)&session->cmd.addr,
+ &session->cmd.addrlen, timeout);
+ if (session->cmd.sd < 0)
+ {
+ /* Only report interesting, infrequent errors (not the common timeout) */
+
+#ifdef CONFIG_DEBUG_NET
+ if (session->cmd.sd != -ETIMEDOUT)
+ {
+ ndbg("ftpd_accept() failed: %d\n", session->cmd.sd);
+ }
+#endif
+ ret = session->cmd.sd;
+ goto errout_with_session;
+ }
+
+ /* And create a worker thread to service the session */
+
+ ret = ftpd_startworker(ftpd_worker, (FAR void *)session,
+ CONFIG_FTPD_WORKERSTACKSIZE);
+ if (ret < 0)
+ {
+ ndbg("ftpd_startworker() failed: %d\n", ret);
+ goto errout_with_session;
+ }
+
+ /* Successfully connected an launched the worker thread */
+
+ return 0;
+
+errout_with_session:
+ ftpd_freesession(session);
+errout:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ftpd_close
+ *
+ * Description:
+ * Close and destroy the handle created by ftpd_open.
+ *
+ * Input Parameters:
+ * handle - A handle previously returned by ftpd_open
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void ftpd_close(FTPD_SESSION handle)
+{
+ struct ftpd_server_s *server;
+ DEBUGASSERT(handle);
+
+ server = (struct ftpd_server_s *)handle;
+ ftpd_account_free(server->head);
+
+ if (server->sd >= 0)
+ {
+ close(server->sd);
+ server->sd = -1;
+ }
+
+ free(server);
+}
+
diff --git a/apps/netutils/ftpd/ftpd.h b/apps/netutils/ftpd/ftpd.h
new file mode 100644
index 000000000..003f8d2bf
--- /dev/null
+++ b/apps/netutils/ftpd/ftpd.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+ * apps/include/ftpd.h
+ *
+ * Copyright (C) 2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_NETUTILS_FTPD_FTPD_H
+#define __APPS_NETUTILS_FTPD_FTPD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+#include <netinet/in.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* FPTD Definitions *********************************************************/
+
+#define FTPD_SESSIONFLAG_USER (1 << 0) /* Session has a user */
+#define FTPD_SESSIONFLAG_RESTARTPOS (1 << 1) /* Session has a restart position */
+#define FTPD_SESSIONFLAG_RENAMEFROM (1 << 2) /* Session has a rename from string */
+
+#define FTPD_LISTOPTION_A (1 << 0) /* List option 'A' */
+#define FTPD_LISTOPTION_L (1 << 1) /* List option 'L' */
+#define FTPD_LISTOPTION_F (1 << 2) /* List option 'F' */
+#define FTPD_LISTOPTION_R (1 << 3) /* List option 'R' */
+#define FTPD_LISTOPTION_UNKNOWN (1 << 7) /* Unknown list option */
+
+#define FTPD_CMDFLAG_LOGIN (1 << 0) /* Command requires login */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+/* This enumerates the type of each session */
+
+enum ftpd_sessiontype_e
+{
+ FTPD_SESSIONTYPE_NONE = 0,
+ FTPD_SESSIONTYPE_A,
+ FTPD_SESSIONTYPE_I,
+ FTPD_SESSIONTYPE_L8
+};
+
+struct ftpd_pathnode_s
+{
+ struct ftpd_pathnode_s *flink;
+ struct ftpd_pathnode_s *blink;
+ bool ignore;
+ FAR char *name;
+};
+
+union ftpd_sockaddr_u
+{
+ uint8_t raw[sizeof(struct sockaddr_storage)];
+ struct sockaddr_storage ss;
+ struct sockaddr sa;
+#ifdef CONFIG_NET_IPv6
+ struct sockaddr_in6 in6;
+#else
+ struct sockaddr_in in4;
+#endif
+};
+
+/* This structure describes on account */
+
+struct ftpd_account_s
+{
+ struct ftpd_account_s *blink;
+ struct ftpd_account_s *flink;
+ uint8_t flags; /* See FTPD_ACCOUNTFLAG_* definitions */
+ FAR char *user; /* User name */
+ FAR char *password; /* Un-encrypted password */
+ FAR char *home; /* Home directory path */
+};
+
+/* This structures describes an FTP session a list of associated accounts */
+
+struct ftpd_server_s
+{
+ int sd; /* Listen socket descriptor */
+ union ftpd_sockaddr_u addr; /* Listen address */
+ struct ftpd_account_s *head; /* Head of a list of accounts */
+ struct ftpd_account_s *tail; /* Tail of a list of accounts */
+};
+
+struct ftpd_stream_s
+{
+ int sd; /* Socket descriptor */
+ union ftpd_sockaddr_u addr; /* Network address */
+ socklen_t addrlen; /* Length of the address */
+ size_t buflen; /* Length of the buffer */
+ char *buffer; /* Pointer to the buffer */
+};
+
+struct ftpd_session_s
+{
+ FAR struct ftpd_server_s *server;
+ FAR struct ftpd_account_s *head;
+ FAR struct ftpd_account_s *curr;
+ uint8_t flags; /* See TPD_SESSIONFLAG_* definitions */
+ int rxtimeout;
+ int txtimeout;
+
+ /* Command */
+
+ struct ftpd_stream_s cmd;
+ FAR char *command;
+ FAR char *param;
+
+ /* Data */
+
+ struct ftpd_stream_s data;
+ off_t restartpos;
+
+ /* File */
+
+ int fd;
+
+ /* Current user */
+
+ FAR char *user;
+ uint8_t type; /* See enum ftpd_sessiontype_e */
+ FAR char *home;
+ FAR char *work;
+ FAR char *renamefrom;
+};
+
+typedef int (*ftpd_cmdhandler_t)(struct ftpd_session_s *);
+
+struct ftpd_cmd_s
+{
+ FAR const char *command; /* The command string */
+ ftpd_cmdhandler_t handler; /* The function that handles the command */
+ uint8_t flags; /* See FTPD_CMDFLAGS_* definitions */
+};
+
+/* Used to maintain a list of protocol names */
+
+struct ftpd_protocol_s
+{
+ FAR const char *name;
+ int value;
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+#endif /* __APPS_NETUTILS_FTPD_FTPD_H */
diff --git a/apps/netutils/resolv/Kconfig b/apps/netutils/resolv/Kconfig
new file mode 100644
index 000000000..f92d732f5
--- /dev/null
+++ b/apps/netutils/resolv/Kconfig
@@ -0,0 +1,17 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_RESOLV
+ bool "Name resolution"
+ default n
+ ---help---
+ Enable support for the name resolution.
+
+config NET_RESOLV_ENTRIES
+ int "Number of resolver entries"
+ default 8
+ depends on NETUTILS_RESOLV
+ ---help---
+ Number of resolver entries. Default: 8
diff --git a/apps/netutils/resolv/Makefile b/apps/netutils/resolv/Makefile
new file mode 100644
index 000000000..89744e323
--- /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 <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
+
+# 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..98d1b28e8
--- /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, 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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/Kconfig b/apps/netutils/smtp/Kconfig
new file mode 100644
index 000000000..99f4e4bd6
--- /dev/null
+++ b/apps/netutils/smtp/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_SMTP
+ bool "SMTP"
+ default n
+ ---help---
+ Enable support for SMTP.
+
+if NETUTILS_SMTP
+endif
diff --git a/apps/netutils/smtp/Makefile b/apps/netutils/smtp/Makefile
new file mode 100644
index 000000000..5a43d1c9d
--- /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 <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
+
+# 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..08ff295ef
--- /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 <gnutt@nuttx.org>
+ *
+ * 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 <nuttx/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/Kconfig b/apps/netutils/telnetd/Kconfig
new file mode 100644
index 000000000..8df8e907b
--- /dev/null
+++ b/apps/netutils/telnetd/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_TELNETD
+ bool "Telet daemon"
+ default n
+ ---help---
+ Enable support for the Telnet daemon.
+
+if NETUTILS_TELNETD
+endif
diff --git a/apps/netutils/telnetd/Makefile b/apps/netutils/telnetd/Makefile
new file mode 100644
index 000000000..fac6df571
--- /dev/null
+++ b/apps/netutils/telnetd/Makefile
@@ -0,0 +1,97 @@
+############################################################################
+# apps/netutils/telnetd/Makefile
+#
+# Copyright (C) 2011-2012 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
+
+# Telnet daemon
+
+ASRCS =
+CSRCS =
+
+ifeq ($(CONFIG_NET_TCP),y)
+CSRCS += telnetd_daemon.c telnetd_driver.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..367cef0a2
--- /dev/null
+++ b/apps/netutils/telnetd/README.txt
@@ -0,0 +1,4 @@
+README.txt
+^^^^^^^^^^
+
+This directly contains a generic Telnet daemon.
diff --git a/apps/netutils/telnetd/telnetd.h b/apps/netutils/telnetd/telnetd.h
new file mode 100644
index 000000000..957c6c550
--- /dev/null
+++ b/apps/netutils/telnetd/telnetd.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+ * apps/netutils/telnetd/telnetd.c
+ *
+ * Copyright (C) 2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_NETUTILS_TELNETD_TELNETD_H
+#define __APPS_NETUTILS_TELNETD_TELNETD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* This structure represents the overall state of one telnet daemon instance
+ * (Yes, multiple telnet daemons are supported).
+ */
+
+struct telnetd_s
+{
+ int port; /* The port to listen on (in network byte order) */
+ int priority; /* The execution priority of the spawned task, */
+ int stacksize; /* The stack size needed by the spawned task */
+ main_t entry; /* The entrypoint of the task to spawn when a new
+ * connection is accepted. */
+};
+
+/* This structure is used to passed information to telnet daemon when it
+ * started. It contains global information visable to all telnet daemons.
+ */
+
+struct telnetd_common_s
+{
+ uint8_t ndaemons; /* The total number of daemons running */
+ sem_t startsem; /* Enforces one-at-a-time startup */
+ sem_t exclsem; /* Enforces exclusive access to 'minor' */
+ FAR struct telnetd_s *daemon; /* Describes the new daemon */
+ int minor; /* The next minor number to use */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* This structure is used to passed information to telnet daemon when it
+ * started. It contains global information visable to all telnet daemons.
+ */
+
+extern struct telnetd_common_s g_telnetdcommon;
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: telnetd_driver
+ *
+ * Description:
+ * Create a character driver to "wrap" the telnet session. This function
+ * will select and return a unique path for the new telnet device.
+ *
+ * Parameters:
+ * sd - The socket descriptor that represents the new telnet connection.
+ * daemon - A pointer to the structure representing the overall state of
+ * this instance of the telnet daemon.
+ *
+ * Return:
+ * An allocated string represent the full path to the created driver. The
+ * receiver of the string must de-allocate this memory when it is no longer
+ * needed. NULL is returned on a failure.
+ *
+ ****************************************************************************/
+
+FAR char *telnetd_driver(int sd, FAR struct telnetd_s *daemon);
+
+#endif /* __APPS_NETUTILS_TELNETD_TELNETD_H */
+
diff --git a/apps/netutils/telnetd/telnetd_daemon.c b/apps/netutils/telnetd/telnetd_daemon.c
new file mode 100644
index 000000000..aea9eb483
--- /dev/null
+++ b/apps/netutils/telnetd/telnetd_daemon.c
@@ -0,0 +1,352 @@
+/****************************************************************************
+ * netutils/telnetd/telnetd_daemon.c
+ *
+ * Copyright (C) 2012 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <sched.h>
+#include <errno.h>
+#include <debug.h>
+#include <netinet/in.h>
+
+#include <apps/netutils/telnetd.h>
+#include <apps/netutils/uiplib.h>
+
+#include "telnetd.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* This structure is used to passed information to telnet daemon when it
+ * started.
+ */
+
+struct telnetd_common_s g_telnetdcommon;
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: telnetd_daemon
+ *
+ * Description:
+ * This function is the Telnet daemon. It does not return (unless an
+ * error occurs).
+ *
+ * Parameters:
+ * Standard task start up arguments.
+ *
+ * Return:
+ * Does not return unless an error occurs.
+ *
+ ****************************************************************************/
+
+static int telnetd_daemon(int argc, char *argv[])
+{
+ FAR struct telnetd_s *daemon;
+ struct sockaddr_in myaddr;
+#ifdef CONFIG_NET_HAVE_SOLINGER
+ struct linger ling;
+#endif
+ socklen_t addrlen;
+ FAR char *devpath;
+ pid_t pid;
+ int listensd;
+ int acceptsd;
+ int drvrfd;
+#ifdef CONFIG_NET_HAVE_REUSEADDR
+ int optval;
+#endif
+
+ /* Get daemon startup info */
+
+ daemon = g_telnetdcommon.daemon;
+ g_telnetdcommon.daemon = NULL;
+ sem_post(&g_telnetdcommon.startsem);
+ DEBUGASSERT(daemon != NULL);
+
+ /* Create a new TCP socket to use to listen for connections */
+
+ listensd = socket(PF_INET, SOCK_STREAM, 0);
+ if (listensd < 0)
+ {
+ int errval = errno;
+ ndbg("socket failure: %d\n", errval);
+ return -errval;
+ }
+
+ /* 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 = daemon->port;
+ 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;
+ }
+
+ /* Now go silent. Only the lldbg family of debug functions should
+ * be used after this point because these do not depend on stdout
+ * being available.
+ */
+
+#ifndef CONFIG_DEBUG
+ close(0);
+ close(1);
+ close(2);
+#endif
+
+ /* Begin accepting connections */
+
+ for (;;)
+ {
+ nllvdbg("Accepting connections on port %d\n", ntohs(daemon->port));
+
+ addrlen = sizeof(struct sockaddr_in);
+ acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen);
+ if (acceptsd < 0)
+ {
+ nlldbg("accept failed: %d\n", errno);
+ goto errout_with_socket;
+ }
+
+ /* 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)
+ {
+ nlldbg("setsockopt failed: %d\n", errno);
+ goto errout_with_acceptsd;
+ }
+#endif
+
+ /* Create a character device to "wrap" the accepted socket descriptor */
+
+ nllvdbg("Creating the telnet driver\n");
+ devpath = telnetd_driver(acceptsd, daemon);
+ if (devpath < 0)
+ {
+ nlldbg("telnetd_driver failed\n");
+ goto errout_with_acceptsd;
+ }
+
+ /* Open the driver */
+
+ nllvdbg("Opening the telnet driver\n");
+ drvrfd = open(devpath, O_RDWR);
+ if (drvrfd < 0)
+ {
+ nlldbg("Failed to open %s: %d\n", devpath, errno);
+ goto errout_with_acceptsd;
+ }
+
+ /* We can now free the driver string */
+
+ free(devpath);
+
+ /* Use this driver as stdin, stdout, and stderror */
+
+ (void)dup2(drvrfd, 0);
+ (void)dup2(drvrfd, 1);
+ (void)dup2(drvrfd, 2);
+
+ /* And we can close our original driver fd */
+
+ if (drvrfd > 2)
+ {
+ close(drvrfd);
+ }
+
+ /* Create a task to handle the connection. The created task
+ * will inherit the new stdin, stdout, and stderr.
+ */
+
+ nllvdbg("Starting the telnet session\n");
+ pid = TASK_CREATE("Telnet session", daemon->priority, daemon->stacksize,
+ daemon->entry, NULL);
+ if (pid < 0)
+ {
+ nlldbg("Failed start the telnet session: %d\n", errno);
+ goto errout_with_acceptsd;
+ }
+
+ /* Forget about the connection. */
+
+ close(0);
+ close(1);
+ close(2);
+ }
+
+errout_with_acceptsd:
+ close(acceptsd);
+
+errout_with_socket:
+ close(listensd);
+ free(daemon);
+ return 1;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: telnetd_start
+ *
+ * Description:
+ * Start the telnet daemon.
+ *
+ * Parameters:
+ * config A pointer to a configuration structure that characterizes the
+ * telnet daemon. This configuration structure may be defined
+ * on the caller's stack because it is not retained by the
+ * daemon.
+ *
+ * Return:
+ * The process ID (pid) of the new telnet daemon is returned on
+ * success; A negated errno is returned if the daemon was not successfully
+ * started.
+ *
+ ****************************************************************************/
+
+int telnetd_start(FAR struct telnetd_config_s *config)
+{
+ FAR struct telnetd_s *daemon;
+ pid_t pid;
+ int ret;
+
+ /* Allocate a state structure for the new daemon */
+
+ daemon = (FAR struct telnetd_s *)malloc(sizeof(struct telnetd_s));
+ if (!daemon)
+ {
+ return -ENOMEM;
+ }
+
+ /* Initialize the daemon structure */
+
+ daemon->port = config->d_port;
+ daemon->priority = config->t_priority;
+ daemon->stacksize = config->t_stacksize;
+ daemon->entry = config->t_entry;
+
+ /* Initialize the common structure if this is the first daemon */
+
+ if (g_telnetdcommon.ndaemons < 1)
+ {
+ sem_init(&g_telnetdcommon.startsem, 0, 0);
+ sem_init(&g_telnetdcommon.exclsem, 0, 1);
+ g_telnetdcommon.minor = 0;
+ }
+
+ /* Then start the new daemon */
+
+ g_telnetdcommon.daemon = daemon;
+ pid = TASK_CREATE("Telnet daemon", config->d_priority, config->d_stacksize,
+ telnetd_daemon, NULL);
+ if (pid < 0)
+ {
+ int errval = errno;
+ free(daemon);
+ ndbg("Failed to start the telnet daemon: %d\n", errval);
+ return -errval;
+ }
+
+ /* Then wait for the daemon to start and complete the handshake */
+
+ do
+ {
+ ret = sem_wait(&g_telnetdcommon.startsem);
+
+ /* The only expected error condition is for sem_wait to be awakened by
+ * a receipt of a signal.
+ */
+
+ if (ret < 0)
+ {
+ DEBUGASSERT(errno == -EINTR);
+ }
+ }
+ while (ret < 0);
+
+ /* Return success */
+
+ return pid;
+}
diff --git a/apps/netutils/telnetd/telnetd_driver.c b/apps/netutils/telnetd/telnetd_driver.c
new file mode 100644
index 000000000..1183a2f70
--- /dev/null
+++ b/apps/netutils/telnetd/telnetd_driver.c
@@ -0,0 +1,813 @@
+/****************************************************************************
+ * apps/netutils/telnetd_driver.c
+ *
+ * Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * This is a leverage of similar logic from uIP which has a compatible BSD
+ * license:
+ *
+ * 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, NuttX nor the names of its 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 <fcntl.h>
+#include <string.h>
+#include <poll.h>
+#include <errno.h>
+#include <nuttx/fs/fs.h>
+#include <debug.h>
+
+#include <nuttx/net/net.h>
+
+#include <apps/netutils/telnetd.h>
+#include <apps/netutils/uiplib.h>
+
+#include "telnetd.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Telnet protocol stuff ****************************************************/
+
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+
+#define TELNET_IAC 255
+#define TELNET_WILL 251
+#define TELNET_WONT 252
+#define TELNET_DO 253
+#define TELNET_DONT 254
+
+/* Device stuff *************************************************************/
+
+#define TELNETD_DEVFMT "/dev/telnetd%d"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+/* The state of the telnet parser */
+
+enum telnetd_state_e
+{
+ STATE_NORMAL = 0,
+ STATE_IAC,
+ STATE_WILL,
+ STATE_WONT,
+ STATE_DO,
+ STATE_DONT
+};
+
+/* This structure describes the internal state of the driver */
+
+struct telnetd_dev_s
+{
+ sem_t td_exclsem; /* Enforces mutually exclusive access */
+ uint8_t td_state; /* (See telnetd_state_e) */
+ uint8_t td_pending; /* Number of valid, pending bytes in the rxbuffer */
+ uint8_t td_offset; /* Offset to the valid, pending bytes in the rxbuffer */
+ uint8_t td_crefs; /* The number of open references to the session */
+ int td_minor; /* Minor device number */
+ FAR struct socket td_psock; /* A clone of the internal socket structure */
+ char td_rxbuffer[CONFIG_TELNETD_RXBUFFER_SIZE];
+ char td_txbuffer[CONFIG_TELNETD_TXBUFFER_SIZE];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+/* Support functions */
+
+#ifdef CONFIG_TELNETD_DUMPBUFFER
+static inline void telnetd_dumpbuffer(FAR const char *msg,
+ FAR const char *buffer, unsigned int nbytes)
+#else
+# define telnetd_dumpbuffer(msg,buffer,nbytes)
+#endif
+static void telnetd_getchar(FAR struct telnetd_dev_s *priv, uint8_t ch,
+ FAR char *dest, int *nread);
+static ssize_t telnetd_receive(FAR struct telnetd_dev_s *priv,
+ FAR const char *src, size_t srclen, FAR char *dest,
+ size_t destlen);
+static bool telnetd_putchar(FAR struct telnetd_dev_s *priv, uint8_t ch,
+ int *nwritten);
+static void telnetd_sendopt(FAR struct telnetd_dev_s *priv, uint8_t option,
+ uint8_t value);
+
+/* Character driver methods */
+
+static int telnetd_open(FAR struct file *filep);
+static int telnetd_close(FAR struct file *filep);
+static ssize_t telnetd_read(FAR struct file *, FAR char *, size_t);
+static ssize_t telnetd_write(FAR struct file *, FAR const char *, size_t);
+static int telnetd_ioctl(FAR struct file *filep, int cmd,
+ unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_telnetdfops =
+{
+ telnetd_open, /* open */
+ telnetd_close, /* close */
+ telnetd_read, /* read */
+ telnetd_write, /* write */
+ 0, /* seek */
+ telnetd_ioctl /* ioctl */
+#ifndef CONFIG_DISABLE_POLL
+ , 0 /* poll */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: telnetd_dumpbuffer
+ *
+ * Description:
+ * Dump a buffer of data (debug only)
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_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);
+}
+#endif
+
+/****************************************************************************
+ * Name: telnetd_getchar
+ *
+ * Description:
+ * Get another character for the user received buffer from the RX buffer
+ *
+ ****************************************************************************/
+
+static void telnetd_getchar(FAR struct telnetd_dev_s *priv, uint8_t ch,
+ FAR char *dest, int *nread)
+{
+ register int index;
+
+ /* Ignore carriage returns */
+
+ if (ch != ISO_cr)
+ {
+ /* Add all other characters to the destination buffer */
+
+ index = *nread;
+ dest[index++] = ch;
+ *nread = index;
+ }
+}
+
+/****************************************************************************
+ * Name: telnetd_receive
+ *
+ * Description:
+ * Process a received telenet buffer
+ *
+ ****************************************************************************/
+
+static ssize_t telnetd_receive(FAR struct telnetd_dev_s *priv, FAR const char *src,
+ size_t srclen, FAR char *dest, size_t destlen)
+{
+ int nread;
+ uint8_t ch;
+
+ nllvdbg("srclen: %d destlen: %d\n", srclen, destlen);
+
+ for (nread = 0; srclen > 0 && nread < destlen; srclen--)
+ {
+ ch = *src++;
+ nllvdbg("ch=%02x state=%d\n", ch, priv->td_state);
+
+ switch (priv->td_state)
+ {
+ case STATE_IAC:
+ if (ch == TELNET_IAC)
+ {
+ telnetd_getchar(priv, ch, dest, &nread);
+ priv->td_state = STATE_NORMAL;
+ }
+ else
+ {
+ switch (ch)
+ {
+ case TELNET_WILL:
+ priv->td_state = STATE_WILL;
+ break;
+
+ case TELNET_WONT:
+ priv->td_state = STATE_WONT;
+ break;
+
+ case TELNET_DO:
+ priv->td_state = STATE_DO;
+ break;
+
+ case TELNET_DONT:
+ priv->td_state = STATE_DONT;
+ break;
+
+ default:
+ priv->td_state = STATE_NORMAL;
+ break;
+ }
+ }
+ break;
+
+ case STATE_WILL:
+ /* Reply with a DONT */
+
+ telnetd_sendopt(priv, TELNET_DONT, ch);
+ priv->td_state = STATE_NORMAL;
+ break;
+
+ case STATE_WONT:
+ /* Reply with a DONT */
+
+ telnetd_sendopt(priv, TELNET_DONT, ch);
+ priv->td_state = STATE_NORMAL;
+ break;
+
+ case STATE_DO:
+ /* Reply with a WONT */
+
+ telnetd_sendopt(priv, TELNET_WONT, ch);
+ priv->td_state = STATE_NORMAL;
+ break;
+
+ case STATE_DONT:
+ /* Reply with a WONT */
+
+ telnetd_sendopt(priv, TELNET_WONT, ch);
+ priv->td_state = STATE_NORMAL;
+ break;
+
+ case STATE_NORMAL:
+ if (ch == TELNET_IAC)
+ {
+ priv->td_state = STATE_IAC;
+ }
+ else
+ {
+ telnetd_getchar(priv, ch, dest, &nread);
+ }
+ break;
+ }
+ }
+
+ /* We get here if (1) all of the received bytes have been processed, or
+ * (2) if the user's buffer has become full.
+ */
+
+ if (srclen > 0)
+ {
+ /* Remember where we left off. These bytes will be returned the next
+ * time that telnetd_read() is called.
+ */
+
+ priv->td_pending = srclen;
+ priv->td_offset = (src - priv->td_rxbuffer);
+ }
+ else
+ {
+ /* All of the received bytes were consumed */
+
+ priv->td_pending = 0;
+ priv->td_offset = 0;
+ }
+
+ return nread;
+}
+
+/****************************************************************************
+ * Name: telnetd_putchar
+ *
+ * Description:
+ * Put another character from the user buffer to the TX buffer.
+ *
+ ****************************************************************************/
+
+static bool telnetd_putchar(FAR struct telnetd_dev_s *priv, uint8_t ch,
+ int *nread)
+{
+ register int index;
+ bool ret = false;
+
+ /* Ignore carriage returns (we will put these in automatically as necesary) */
+
+ if (ch != ISO_cr)
+ {
+ /* Add all other characters to the destination buffer */
+
+ index = *nread;
+ priv->td_txbuffer[index++] = ch;
+
+ /* Check for line feeds */
+
+ if (ch == ISO_nl)
+ {
+ /* Now add the carriage return */
+
+ priv->td_txbuffer[index++] = ISO_cr;
+ priv->td_txbuffer[index++] = '\0';
+
+ /* End of line */
+
+ ret = true;
+ }
+
+ *nread = index;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: telnetd_sendopt
+ *
+ * Description:
+ * Send the telnet option bytes
+ *
+ ****************************************************************************/
+
+static void telnetd_sendopt(FAR struct telnetd_dev_s *priv, 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 (psock_send(&priv->td_psock, optbuf, 4, 0) < 0)
+ {
+ nlldbg("Failed to send TELNET_IAC\n");
+ }
+}
+
+/****************************************************************************
+ * Name: telnetd_open
+ ****************************************************************************/
+
+static int telnetd_open(FAR struct file *filep)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct telnetd_dev_s *priv = inode->i_private;
+ int tmp;
+ int ret;
+
+ nllvdbg("td_crefs: %d\n", priv->td_crefs);
+
+ /* O_NONBLOCK is not supported */
+
+ if (filep->f_oflags & O_NONBLOCK)
+ {
+ ret = -ENOSYS;
+ goto errout;
+ }
+
+ /* Get exclusive access to the device structures */
+
+ ret = sem_wait(&priv->td_exclsem);
+ if (ret < 0)
+ {
+ ret = -errno;
+ goto errout;
+ }
+
+ /* Increment the count of references to the device. If this the first
+ * time that the driver has been opened for this device, then initialize
+ * the device.
+ */
+
+ tmp = priv->td_crefs + 1;
+ if (tmp > 255)
+ {
+ /* More than 255 opens; uint8_t would overflow to zero */
+
+ ret = -EMFILE;
+ goto errout_with_sem;
+ }
+
+ /* Save the new open count on success */
+
+ priv->td_crefs = tmp;
+ ret = OK;
+
+errout_with_sem:
+ sem_post(&priv->td_exclsem);
+
+errout:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: telnetd_close
+ ****************************************************************************/
+
+static int telnetd_close(FAR struct file *filep)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct telnetd_dev_s *priv = inode->i_private;
+ FAR char *devpath;
+ int ret;
+
+ nllvdbg("td_crefs: %d\n", priv->td_crefs);
+
+ /* Get exclusive access to the device structures */
+
+ ret = sem_wait(&priv->td_exclsem);
+ if (ret < 0)
+ {
+ ret = -errno;
+ goto errout;
+ }
+
+ /* Decrement the references to the driver. If the reference count will
+ * decrement to 0, then uninitialize the driver.
+ */
+
+ if (priv->td_crefs > 1)
+ {
+ /* Just decrement the reference count and release the semaphore */
+
+ priv->td_crefs--;
+ sem_post(&priv->td_exclsem);
+ }
+ else
+ {
+ /* Re-create the path to the driver. */
+
+ sched_lock();
+ ret = asprintf(&devpath, TELNETD_DEVFMT, priv->td_minor);
+ if (ret < 0)
+ {
+ nlldbg("Failed to allocate the driver path\n");
+ }
+ else
+ {
+ /* Unregister the character driver */
+
+ ret = unregister_driver(devpath);
+ if (ret < 0)
+ {
+ nlldbg("Failed to unregister the driver %s: %d\n", ret);
+ }
+
+ free(devpath);
+ }
+
+ /* Close the socket */
+
+ psock_close(&priv->td_psock);
+
+ /* Release the driver memory. What if there are threads waiting on
+ * td_exclsem? They will never be awakened! How could this happen?
+ * crefs == 1 so there are no other open references to the driver.
+ * But this could have if someone were trying to re-open the driver
+ * after every other thread has closed it. That really should not
+ * happen in the intended usage model.
+ */
+
+ DEBUGASSERT(priv->td_exclsem.semcount == 0);
+ sem_destroy(&priv->td_exclsem);
+ free(priv);
+ sched_unlock();
+ }
+
+ ret = OK;
+
+errout:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: telnetd_read
+ ****************************************************************************/
+
+static ssize_t telnetd_read(FAR struct file *filep, FAR char *buffer, size_t len)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct telnetd_dev_s *priv = inode->i_private;
+ ssize_t ret;
+
+ nllvdbg("len: %d\n", len);
+
+ /* First, handle the case where there are still valid bytes left in the
+ * I/O buffer from the last time that read was called. NOTE: Much of
+ * what we read may be protocol stuff and may not correspond to user
+ * data. Hence we need the loop and we need may need to call psock_recv()
+ * multiple times in order to get data that the client is interested in.
+ */
+
+ do
+ {
+ if (priv->td_pending > 0)
+ {
+ FAR const char *src = &priv->td_rxbuffer[priv->td_offset];
+ ret = telnetd_receive(priv, src, priv->td_pending, buffer, len);
+ }
+
+ /* Read a buffer of data from the telnet client */
+
+ else
+ {
+ ret = psock_recv(&priv->td_psock, priv->td_rxbuffer,
+ CONFIG_TELNETD_RXBUFFER_SIZE, 0);
+ if (ret > 0)
+ {
+ /* Process the received telnet data */
+
+ telnetd_dumpbuffer("Received buffer", priv->td_rxbuffer, ret);
+ ret = telnetd_receive(priv, priv->td_rxbuffer, ret, buffer, len);
+ }
+ }
+ }
+ while (ret == 0);
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: telnetd_write
+ ****************************************************************************/
+
+static ssize_t telnetd_write(FAR struct file *filep, FAR const char *buffer, size_t len)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct telnetd_dev_s *priv = inode->i_private;
+ FAR const char *src = buffer;
+ ssize_t nsent;
+ ssize_t ret;
+ int ncopied;
+ char ch;
+ bool eol;
+
+ nllvdbg("len: %d\n", len);
+
+ /* Process each character from the user buffer */
+
+ for (nsent = 0, ncopied = 0; nsent < len; nsent++)
+ {
+ /* Get the next character from the user buffer */
+
+ ch = *src++;
+
+ /* Add the character to the TX buffer */
+
+ eol = telnetd_putchar(priv, ch, &ncopied);
+
+ /* Was that the end of a line? Or is the buffer too full to hold the
+ * next largest character sequence ("\r\n\0")?
+ */
+
+ if (eol || ncopied > CONFIG_TELNETD_TXBUFFER_SIZE-3)
+ {
+ /* Yes... send the data now */
+
+ ret = psock_send(&priv->td_psock, priv->td_txbuffer, ncopied, 0);
+ if (ret < 0)
+ {
+ nlldbg("psock_send failed '%s': %d\n", priv->td_txbuffer, ret);
+ return ret;
+ }
+
+ /* Reset the index to the beginning of the TX buffer. */
+
+ ncopied = 0;
+ }
+ }
+
+ /* Send anything remaining in the TX buffer */
+
+ if (ncopied > 0)
+ {
+ ret = psock_send(&priv->td_psock, priv->td_txbuffer, ncopied, 0);
+ if (ret < 0)
+ {
+ nlldbg("psock_send failed '%s': %d\n", priv->td_txbuffer, ret);
+ return ret;
+ }
+ }
+
+ /* Notice that we don't actually return the number of bytes sent, but
+ * rather, the number of bytes that the caller asked us to send. We may
+ * have sent more bytes (because of CR-LF expansion and because of NULL
+ * termination). But it confuses some logic if you report that you sent
+ * more than you were requested to.
+ */
+
+ return len;
+}
+
+/****************************************************************************
+ * Name: telnetd_poll
+ ****************************************************************************/
+
+static int telnetd_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+#if 0 /* No ioctl commands are yet supported */
+ struct inode *inode = filep->f_inode;
+ struct cdcacm_dev_s *priv = inode->i_private;
+ int ret = OK;
+
+ switch (cmd)
+ {
+ /* Add ioctl commands here */
+
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
+#else
+ return -ENOTTY;
+#endif
+}
+
+/****************************************************************************
+ * Name: telnetd_poll
+ ****************************************************************************/
+
+#if 0 /* Not used by this driver */
+static int telnetd_poll(FAR struct file *filep, FAR struct pollfd *fds,
+ bool setup)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct telnetd_dev_s *priv = inode->i_private;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: telnetd_driver
+ *
+ * Description:
+ * Create a character driver to "wrap" the telnet session. This function
+ * will select and return a unique path for the new telnet device.
+ *
+ * Parameters:
+ * sd - The socket descriptor that represents the new telnet connection.
+ * daemon - A pointer to the structure representing the overall state of
+ * this instance of the telnet daemon.
+ *
+ * Return:
+ * An allocated string represent the full path to the created driver. The
+ * receiver of the string must de-allocate this memory when it is no longer
+ * needed. NULL is returned on a failure.
+ *
+ ****************************************************************************/
+
+FAR char *telnetd_driver(int sd, FAR struct telnetd_s *daemon)
+{
+ FAR struct telnetd_dev_s *priv;
+ FAR struct socket *psock;
+ FAR char *devpath = NULL;
+ int ret;
+
+ /* Allocate instance data for this driver */
+
+ priv = (FAR struct telnetd_dev_s*)malloc(sizeof(struct telnetd_dev_s));
+ if (!priv)
+ {
+ nlldbg("Failed to allocate the driver data structure\n");
+ return NULL;
+ }
+
+ /* Initialize the allocated driver instance */
+
+ sem_init(&priv->td_exclsem, 0, 1);
+
+ priv->td_state = STATE_NORMAL;
+ priv->td_crefs = 0;
+ priv->td_pending = 0;
+ priv->td_offset = 0;
+
+ /* Clone the internal socket structure. We do this so that it will be
+ * independent of threads and of socket descriptors (the original socket
+ * instance resided in the daemon's socket array).
+ */
+
+ psock = sockfd_socket(sd);
+ if (!psock)
+ {
+ nlldbg("Failed to convert sd=%d to a socket structure\n", sd);
+ goto errout_with_dev;
+ }
+
+ ret = net_clone(psock, &priv->td_psock);
+ if (ret < 0)
+ {
+ nlldbg("net_clone failed: %d\n", ret);
+ goto errout_with_dev;
+ }
+
+ /* And close the original */
+
+ psock_close(psock);
+
+ /* Allocation a unique minor device number of the telnet drvier */
+
+ do
+ {
+ ret = sem_wait(&g_telnetdcommon.exclsem);
+ if (ret < 0 && errno != -EINTR)
+ {
+ goto errout_with_dev;
+ }
+ }
+ while (ret < 0);
+
+ priv->td_minor = g_telnetdcommon.minor;
+ g_telnetdcommon.minor++;
+ sem_post(&g_telnetdcommon.exclsem);
+
+ /* Create a path and name for the driver. */
+
+ ret = asprintf(&devpath, TELNETD_DEVFMT, priv->td_minor);
+ if (ret < 0)
+ {
+ nlldbg("Failed to allocate the driver path\n");
+ goto errout_with_dev;
+ }
+
+ /* Register the driver */
+
+ ret = register_driver(devpath, &g_telnetdfops, 0666, priv);
+ if (ret < 0)
+ {
+ nlldbg("Failed to register the driver %s: %d\n", devpath, ret);
+ goto errout_with_devpath;
+ }
+
+ /* Return the path to the new telnet driver */
+
+ return devpath;
+
+errout_with_devpath:
+ free(devpath);
+errout_with_dev:
+ free(priv);
+ return NULL;
+}
+
+
+
diff --git a/apps/netutils/tftpc/Kconfig b/apps/netutils/tftpc/Kconfig
new file mode 100644
index 000000000..e2edcd6ac
--- /dev/null
+++ b/apps/netutils/tftpc/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_TFTPC
+ bool "TFTP client"
+ default n
+ ---help---
+ Enable support for the TFTP client.
+
+if NETUTILS_TFTPC
+endif
diff --git a/apps/netutils/tftpc/Makefile b/apps/netutils/tftpc/Makefile
new file mode 100644
index 000000000..910046c11
--- /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 <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
+
+# 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..697021d95
--- /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 <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, 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 <nuttx/net/uip/uipopt.h>
+#include <nuttx/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..f689ce176
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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 <nuttx/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..7d172e659
--- /dev/null
+++ b/apps/netutils/tftpc/tftpc_packets.c
@@ -0,0 +1,330 @@
+/****************************************************************************
+ * netuils/tftp/tftpc_packets.c
+ *
+ * Copyright (C) 2008-2009, 2011-2012 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, 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 <nuttx/net/uip/uipopt.h>
+#include <nuttx/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..76ef18a8c
--- /dev/null
+++ b/apps/netutils/tftpc/tftpc_put.c
@@ -0,0 +1,485 @@
+/****************************************************************************
+ * netuils/tftp/tftpc_put.c
+ *
+ * Copyright (C) 2008-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, 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 <nuttx/net/uip/uipopt.h>
+#include <nuttx/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("Connection lost: %d bytes\n", nbytes);
+ }
+ else if (nbytes > 0)
+ {
+ ndbg("Short packet: %d bytes\n", nbytes);
+ }
+ else
+ {
+ ndbg("Recveid failure\n");
+ }
+
+ /* 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/Kconfig b/apps/netutils/thttpd/Kconfig
new file mode 100644
index 000000000..aa3751839
--- /dev/null
+++ b/apps/netutils/thttpd/Kconfig
@@ -0,0 +1,240 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_THTTPD
+ bool "THTTPD webserver"
+ default n
+ ---help---
+ Enable support for the THTTPD webservert.
+
+if NETUTILS_THTTPD
+config THTTPD_PORT
+ int "THTTPD port number"
+ default 80
+ ---help---
+ THTTPD Server port number. Default: 80
+
+config THTTPD_IPADDR
+ hex "THTTPD IP address"
+ default 0x10000002
+ ---help---
+ Server IP address (no host name). Default: 0x10000002
+
+ This is a 32-bit integer value in host order. So, as an example,
+ the default value of 0x10000002 would correspond to 10.0.0.2.
+
+config THTTPD_SERVER_ADDRESS
+ string "Reported server URL"
+ default "http://www.nuttx.org"
+ ---help---
+ SERVER_ADDRESS: response, Default: "http://www.nuttx.org"
+
+config THTTPD_SERVER_SOFTWARE
+ string "Reporter server software string"
+ default "thttpd/2.25b 29dec2003-NuttX"
+ ---help---
+ SERVER_SOFTWARE: response, Default: "thttpd/2.25b 29dec2003-NuttX"
+
+config THTTPD_PATH
+ string "Path to the server content"
+ default "/mnt/www"
+ ---help---
+ Server working directory. Default: "/mnt/www"
+
+config THTTPD_CGI_PATH
+ string "Path to CGI content"
+ default "/mnt/www/cgi-bin"
+ ---help---
+ Path to CGI executables. Default: "/mnt/www/cgi-bin"
+
+config THTTPD_CGI_PATTERN
+ string "CGI match pattern"
+ default "/mnt/www/cgi-bin/*"
+ ---help---
+ Only CGI programs matching this pattern will be executed. In
+ fact, if this value is not defined then no CGI logic will be built.
+ Default: "/mnt/www/cgi-bin/*"
+
+config THTTPD_CGI_PRIORITY
+ int "CGI child priority"
+ default 50
+ ---help---
+ Provides the priority of CGI child tasks. Default: 50
+
+config THTTPD_CGI_STACKSIZE
+ int "CGI child stack size"
+ default 2048
+ ---help---
+ Provides the default stack size of CGI child task (will be overridden
+ by the stack size in the NXFLAT header)
+
+config THTTPD_CGI_BYTECOUNT
+ int "Byte output limit"
+ default 200000
+ ---help---
+ Byte output limit for CGI tasks. Default: 200000
+
+config THTTPD_CGI_TIMELIMIT
+ int "CGI time limit"
+ default 0
+ ---help---
+ How many seconds to allow CGI programs to run before killing them.
+ Default: 0 (no time limit)
+
+config THTTPD_CHARSET
+ string "Default character set"
+ default "iso-8859-1"
+ ---help---
+ The default character set name to use with text MIME types.
+ Default: "iso-8859-1"
+
+config THTTPD_IOBUFFERSIZE
+ int "Initial I/O buffer size"
+ default 256
+ ---help---
+ Initial I/O buffer size. Default: 256
+
+config THTTPD_MINSTRSIZE
+ int "Minimum string size"
+ default 64
+ ---help---
+ Minimum string size. Default: 64
+
+config THTTPD_REALLOCINCR
+ int "String reallocation increment"
+ default 64
+ ---help---
+ String reallocation increment. Default: 64
+
+config THTTPD_MAXREALLOC
+ int "Maximum string reallocation size"
+ default 4096
+ ---help---
+ Maximum string reallocation size. Default: 4096
+
+config THTTPD_CGIINBUFFERSIZ
+ int "CGI interpose input buffer size"
+ default 512
+ ---help---
+ CGI interpose input buffer size. Default: 512
+
+config THTTPD_CGIOUTBUFFERSIZE
+ int "CGI interpose output buffer size"
+ default 512
+ ---help---
+ CGI interpose output buffer size. Default: 512
+
+config THTTPD_INDEX_NAMES
+ string "Index file name list"
+ default "\"index.html\", \"index.htm\", \"index.cgi\""
+ ---help---
+ A list of index filenames to check. The files are searched for
+ in this order. Default: "\"index.html\", \"index.htm\", \"index.cgi\""
+
+config AUTH_FILE
+ string "Authorization file"
+# default ".htpasswd"
+ ---help---
+ 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"
+
+config THTTPD_LISTEN_BACKLOG
+ int "Listen backlog"
+ default 8
+ ---help---
+ The listen() backlog queue length. Default: 8
+
+config THTTPD_LINGER_MSEC
+ int "Linger time (msec)"
+ default 500
+ ---help---
+ How many milliseconds to leave a connection open while doing a lingering
+ close. Default: 500
+
+config THTTPD_OCCASIONAL_MSEC
+ int "Occasional clean-up time (msec)"
+ default 120
+ ---help---
+ How often to run the occasional cleanup job in milliseconds.
+ Default: 120 (2 minutes)
+
+config THTTPD_MEMDEBUG
+ bool "Enable memory debug"
+ default n
+ depends on DEBUG && DEBUG_NET
+ ---help---
+ Enable THTTPD memory usage debug output. Default: n
+
+config THTTPD_IDLE_READ_LIMIT_SEC
+ int "Idle read time limit (sec)"
+ default 300
+ ---help---
+ How many seconds to allow for reading the initial request on a new connection.
+ Default: 300
+
+config THTTPD_IDLE_SEND_LIMIT_SEC
+ int "Idle send time limit (sec)"
+ default 300
+ ---help---
+ How many seconds before an idle connection gets closed.
+ Default: 300
+
+config THTTPD_TILDE_MAP1
+ string "Tilde mapping"
+ ---help---
+ 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 THTTPD_TILDE_MAP2.
+
+config THTTPD_TILDE_MAP2
+ string "Tilde mapping"
+ ---help---
+ 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 THTTPD_TILDE_MAP2.
+
+config THTTPD_GENERATE_INDICES
+ bool "Generate name indices"
+ default n
+ ---help---
+
+config THTTPD_URLPATTERN
+ string "URL pattern"
+ ---help---
+ If defined, then it will be used to match and verify referrers.
+
+endif
diff --git a/apps/netutils/thttpd/Makefile b/apps/netutils/thttpd/Makefile
new file mode 100644
index 000000000..f505125da
--- /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 <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
+
+# 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..60efb08e7
--- /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 <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
+
+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..575bf85ba
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..d91a715da
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..c8bdab4ed
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..d238fabd8
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..50ea65e78
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..38a5ecbc0
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..ee0ac999c
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..b245a6edf
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..958192758
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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..e91ab5ebb
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..eea82d7cb
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..1b074902d
--- /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 <gnutt@nuttx.org>
+ *
+ * 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 100644
index 000000000..12872f192
--- /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 <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 <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 100644
index 000000000..e8c8f80c3
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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 100644
index 000000000..9c0de509b
--- /dev/null
+++ b/apps/netutils/thttpd/thttpd_cgi.c
@@ -0,0 +1,1081 @@
+/****************************************************************************
+ * netutils/thttpd/thttpd_cgi.c
+ * CGI support
+ *
+ * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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[2];
+ 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;
+ argv[1] = NULL;
+
+#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 100644
index 000000000..47923223c
--- /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 <gnutt@nuttx.org>
+ *
+ * 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 100644
index 000000000..5795e3754
--- /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 <gnutt@nuttx.org>
+ *
+ * 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 100644
index 000000000..dc05f6295
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..dc94306b0
--- /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 <gnutt@nuttx.org>
+ *
+ * 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..7c8f9f201
--- /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 <gnutt@nuttx.org>
+ *
+ * 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/Kconfig b/apps/netutils/uiplib/Kconfig
new file mode 100644
index 000000000..2eb098717
--- /dev/null
+++ b/apps/netutils/uiplib/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_UIPLIB
+ bool "Network support library"
+ default n
+ ---help---
+ Enable support for the network support library.
+
+if NETUTILS_UIPLIB
+endif
diff --git a/apps/netutils/uiplib/Makefile b/apps/netutils/uiplib/Makefile
new file mode 100644
index 000000000..189b32acc
--- /dev/null
+++ b/apps/netutils/uiplib/Makefile
@@ -0,0 +1,112 @@
+############################################################################
+# apps/netutils/uiplib/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
+
+# UIP Library
+
+ASRCS =
+CSRCS = uiplib.c uip_sethostaddr.c uip_gethostaddr.c uip_setdraddr.c \
+ uip_setnetmask.c uip_parsehttpurl.c
+
+# These require TCP support
+
+ifeq ($(CONFIG_NET_TCP),y)
+CSRCS += uip_server.c uip_listenon.c
+endif
+
+# 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..c5c70b1be
--- /dev/null
+++ b/apps/netutils/uiplib/uip_gethostaddr.c
@@ -0,0 +1,105 @@
+/****************************************************************************
+ * netutils/uiplib/uip_gethostaddr.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>
+#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
+ 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..f4f01a7f3
--- /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 <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>
+#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 100644
index 000000000..8b8b8e77a
--- /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 <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/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_listenon.c b/apps/netutils/uiplib/uip_listenon.c
new file mode 100644
index 000000000..7b61747fb
--- /dev/null
+++ b/apps/netutils/uiplib/uip_listenon.c
@@ -0,0 +1,131 @@
+/****************************************************************************
+ * netutils/uiplib/uip_listenon.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
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <debug.h>
+#include <netinet/in.h>
+
+#include <apps/netutils/uiplib.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: uip_listenon
+ *
+ * Description:
+ * Implement basic server listening
+ *
+ * Parameters:
+ * portno The port to listen on (in network byte order)
+ *
+ * Return:
+ * A valid listening socket or -1 on error.
+ *
+ ****************************************************************************/
+
+int uip_listenon(uint16_t portno)
+{
+ struct sockaddr_in myaddr;
+ int listensd;
+#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 ERROR;
+ }
+
+ /* 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));
+ return listensd;
+
+errout_with_socket:
+ close(listensd);
+ return ERROR;
+}
diff --git a/apps/netutils/uiplib/uip_parsehttpurl.c b/apps/netutils/uiplib/uip_parsehttpurl.c
new file mode 100644
index 000000000..da973b46f
--- /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 <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 <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..d7d1d2c2a
--- /dev/null
+++ b/apps/netutils/uiplib/uip_server.c
@@ -0,0 +1,150 @@
+/****************************************************************************
+ * netutils/uiplib/uip_server.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
+ ****************************************************************************/
+
+#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;
+
+ /* Create a new TCP socket to use to listen for connections */
+
+ listensd = uip_listenon(portno);
+ if (listensd < 0)
+ {
+ return;
+ }
+
+ /* Begin serving connections */
+
+ 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);
+ }
+
+ close(listensd);
+}
diff --git a/apps/netutils/uiplib/uip_setdraddr.c b/apps/netutils/uiplib/uip_setdraddr.c
new file mode 100644
index 000000000..5b7a2183e
--- /dev/null
+++ b/apps/netutils/uiplib/uip_setdraddr.c
@@ -0,0 +1,116 @@
+/****************************************************************************
+ * netutils/uiplib/uip_setdraddr.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>
+#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
+ 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..3cc73faed
--- /dev/null
+++ b/apps/netutils/uiplib/uip_sethostaddr.c
@@ -0,0 +1,116 @@
+/****************************************************************************
+ * netutils/uiplib/uip_sethostaddr.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>
+#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
+ 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..f6cbe4132
--- /dev/null
+++ b/apps/netutils/uiplib/uip_setmacaddr.c
@@ -0,0 +1,114 @@
+/****************************************************************************
+ * netutils/uiplib/uip_setmacaddr.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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>
+#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..7ebe83f85
--- /dev/null
+++ b/apps/netutils/uiplib/uip_setnetmask.c
@@ -0,0 +1,115 @@
+/****************************************************************************
+ * netutils/uiplib/uip_setnetmask.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>
+#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
+ 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..f863b7343
--- /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 <gnutt@nuttx.org>
+ *
+ * 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 <nuttx/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/Kconfig b/apps/netutils/webclient/Kconfig
new file mode 100644
index 000000000..c53195d48
--- /dev/null
+++ b/apps/netutils/webclient/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_WEBCLIENT
+ bool "uIP web client"
+ default n
+ ---help---
+ Enable support for the uIP web client.
+
+if NETUTILS_WEBCLIENT
+endif
diff --git a/apps/netutils/webclient/Makefile b/apps/netutils/webclient/Makefile
new file mode 100644
index 000000000..d999d47af
--- /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 <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
+
+# 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..05a63ba38
--- /dev/null
+++ b/apps/netutils/webclient/webclient.c
@@ -0,0 +1,584 @@
+/****************************************************************************
+ * netutils/webclient/webclient.c
+ * Implementation of the HTTP client.
+ *
+ * Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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)
+ {
+ nvdbg("Connection lost\n");
+ 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/Kconfig b/apps/netutils/webserver/Kconfig
new file mode 100644
index 000000000..6afbda4b3
--- /dev/null
+++ b/apps/netutils/webserver/Kconfig
@@ -0,0 +1,92 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_WEBSERVER
+ bool "uIP web server"
+ default n
+ ---help---
+ Enable support for the uIP web server. This tiny web server was
+ from uIP 1.0, but has undergone many changes. It is, however,
+ still referred to as the "uIP" web server.
+
+if NETUTILS_WEBSERVER
+
+config NETUTILS_HTTPD_SCRIPT_DISABLE
+ bool "Disable %! scripting"
+ default y if NETUTILS_HTTPD_SENDFILE
+ default n if !NETUTILS_HTTPD_SENDFILE
+ ---help---
+ This option, if selected, will elide the %! scripting
+
+config NETUTILS_HTTPD_CGIPATH
+ bool "URL/CGI function mapping"
+ default n
+ ---help---
+ This option enables mappings from URLs to call CGI functions. The
+ effect is that the existing httpd_cgi_register() interface can be
+ used thus:
+
+ const static struct httpd_cgi_call a[] = {
+ { NULL, "/abc", cgi_abc },
+ { NULL, "/xyz", cgi_xyz }
+ };
+
+ for (i = 0; i < sizeof a / sizeof *a; i++) {
+ httpd_cgi_register(&a[i]);
+ }
+
+ Where (under CONFIG_NETUTILS_HTTPD_CGIPATH) the "/xyz" is a URL path,
+ rather than a %! xyz style call in the existing manner.
+
+ This is useful when CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE is defined.
+
+ In other words, this provides a way to get your CGI functions called
+ without needing the scripting language. I'm using this to provide a
+ REST style interface over HTTP, where my CGI handlers just return a
+ HTTP status code with a content length of 0.
+
+config NETUTILS_HTTPD_SERVERHEADER_DISABLE
+ bool "Disabled the SERVER header"
+ default n
+ ---help---
+ This option, if selected, will elide the Server\: header
+
+choice
+ prompt "File Transfer Method"
+ default NETUTILS_HTTPD_CLASSIC
+
+config NETUTILS_HTTPD_CLASSIC
+ bool "Pre-processed files"
+ ---help---
+ Traditionally, the uIP-based webserver only sends "files" that have
+ been prepared as a data structure using nutts/tools/mkfsdata.pl
+
+config NETUTILS_HTTPD_MMAP
+ bool "File mmap-ing"
+ ---help---
+ Traditionally, the uIP-based webserver only sends "files" that have
+ been prepared as a data structure using nutts/tools/mkfsdata.pl
+ However, extensions have been contributed. If this option is
+ selected, then files can be accessed from the NuttX file system
+ as well. This selection will map the files into memory (using mmap)
+ so that the logic is still basically compatible with the classic
+ approach. NOTE, however, that since files are copied into memory,
+ this limits solution to small files that will fit into available RAM.
+
+config NETUTILS_HTTPD_MMAP
+ bool "sendfile()"
+ select NETUTILS_HTTPD_SCRIPT_DISABLE
+ ---help---
+ Traditionally, the uIP-based webserver only sends "files" that have
+ been prepared as a data structure using nutts/tools/mkfsdata.pl
+ However, extensions have been contributed. If this option is
+ selected, then files can be accessed from the NuttX file system
+ as well. This selection will use the NuttX sendfile() interface
+ to send files. NOTE: If this option is selected, then scripting
+ must be disabled since it depends on the classic, in-memory
+ representation.
+
+endchoice
+endif
diff --git a/apps/netutils/webserver/Makefile b/apps/netutils/webserver/Makefile
new file mode 100644
index 000000000..4b1f2f9f3
--- /dev/null
+++ b/apps/netutils/webserver/Makefile
@@ -0,0 +1,104 @@
+############################################################################
+# apps/netutils/webserver/Makefile
+#
+# Copyright (C) 2011-2012 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
+
+# Web server library
+
+ASRCS =
+CSRCS =
+
+ifeq ($(CONFIG_NET_TCP),y)
+CSRCS = httpd.c httpd_cgi.c
+ifeq ($(CONFIG_NETUTILS_HTTPD_SENDFILE),y)
+CSRCS += httpd_sendfile.c
+else ifeq ($(CONFIG_NETUTILS_HTTPD_MMAP),y)
+CSRCS += httpd_mmap.c
+else
+CSRCS += httpd_fs.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/webserver/httpd.c b/apps/netutils/webserver/httpd.c
new file mode 100644
index 000000000..b482b1e03
--- /dev/null
+++ b/apps/netutils/webserver/httpd.c
@@ -0,0 +1,635 @@
+/****************************************************************************
+ * netutils/webserver/httpd.c
+ * httpd Web server
+ *
+ * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <nuttx/net/uip/uip.h>
+#include <apps/netutils/uiplib.h>
+#include <apps/netutils/httpd.h>
+
+#include "httpd.h"
+#include "httpd_cgi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE) && defined(CONFIG_NETUTILS_HTTPD_SENDFILE)
+# error "Script support and CONFIG_NETUTILS_HTTPD_SENDFILE are mutually exclusive"
+#endif
+
+#if defined(CONFIG_NETUTILS_HTTPD_SENDFILE) && defined(CONFIG_NETUTILS_HTTPD_MMAP)
+# error "CONFIG_NETUTILS_HTTPD_SENDFILE and CONFIG_NETUTILS_HTTPD_MMAP are mutually exclusive"
+#endif
+
+#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
+
+#ifndef CONFIG_NETUTILS_HTTPD_PATH
+# define CONFIG_NETUTILS_HTTPD_PATH "/mnt"
+#endif
+
+/****************************************************************************
+ * 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_httpcontenttypejs[] = "Content-type: text/javascript\r\n\r\n";
+
+#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
+static const char g_httpextensionshtml[] = ".shtml";
+#endif
+static const char g_httpextensionhtml[] = ".html";
+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_httpextensionjs[] = ".js";
+
+static const char g_http404path[] = "/404.html";
+#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
+static const char g_httpindexpath[] = "/index.shtml";
+#else
+static const char g_httpindexpath[] = "/index.html";
+#endif
+
+static const char g_httpcmdget[] = "GET ";
+
+static const char g_httpheader200[] =
+ "HTTP/1.0 200 OK\r\n"
+#ifndef CONFIG_NETUTILS_HTTPD_SERVERHEADER_DISABLE
+ "Server: uIP/1.0 http://www.sics.se/~adam/uip/\r\n"
+#endif
+ "Connection: close\r\n";
+
+static const char g_httpheader404[] =
+ "HTTP/1.0 404 Not found\r\n"
+#ifndef CONFIG_NETUTILS_HTTPD_SERVERHEADER_DISABLE
+ "Server: uIP/1.0 http://www.sics.se/~adam/uip/\r\n"
+#endif
+ "Connection: close\r\n";
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int httpd_open(const char *name, struct httpd_fs_file *file)
+{
+#if defined(CONFIG_NETUTILS_HTTPD_SENDFILE)
+ return httpd_sendfile_open(name, file);
+#elif defined(CONFIG_NETUTILS_HTTPD_MMAP)
+ return httpd_mmap_open(name, file);
+#else
+ return httpd_fs_open(name, file);
+#endif
+}
+
+static int httpd_close(struct httpd_fs_file *file)
+{
+#if defined(CONFIG_NETUTILS_HTTPD_SENDFILE)
+ return httpd_sendfile_close(file);
+#elif defined(CONFIG_NETUTILS_HTTPD_MMAP)
+ return httpd_mmap_close(file);
+#else
+ return OK;
+#endif
+}
+
+#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
+
+#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
+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;
+}
+#endif
+
+#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
+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)
+ {
+ if (httpd_open(pstate->ht_scriptptr + 1, &pstate->ht_file) != OK)
+ {
+ return ERROR;
+ }
+
+ send(pstate->ht_sockfd, pstate->ht_file.data, pstate->ht_file.len, 0);
+
+ httpd_close(&pstate->ht_file);
+ }
+ else
+ {
+ httpd_cgifunction f;
+
+ f = httpd_cgi(pstate->ht_scriptptr);
+ if (f != NULL)
+ {
+ f(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;
+}
+#endif
+
+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 httpd_flush(struct httpd_state *pstate)
+{
+ int ret = 0;
+
+ if (pstate->ht_sndlen > 0)
+ {
+ httpd_dumpbuffer("Outgoing buffer", pstate->ht_buffer, pstate->ht_sndlen);
+ ret = send(pstate->ht_sockfd, pstate->ht_buffer, pstate->ht_sndlen, 0);
+ if (ret >= 0)
+ {
+ pstate->ht_sndlen = 0;
+ }
+ }
+ return ret;
+}
+
+static int send_headers(struct httpd_state *pstate, const char *statushdr, int len)
+{
+ char *ptr;
+ int ret;
+ nvdbg("HEADER\n");
+ 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
+#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
+ || strncmp(g_httpextensionshtml, ptr, strlen(g_httpextensionshtml)) == 0
+#endif
+ )
+ {
+ 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 if (strncmp(g_httpextensionjs, ptr, strlen(g_httpextensionjs)) == 0)
+ {
+ ret = httpd_addchunk(pstate, g_httpcontenttypejs, strlen(g_httpcontenttypejs));
+ }
+ else
+ {
+ ret = httpd_addchunk(pstate, g_httpcontenttypeplain, strlen(g_httpcontenttypeplain));
+ }
+
+ return ret;
+}
+
+static int httpd_sendfile(struct httpd_state *pstate)
+{
+#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
+ char *ptr;
+#endif
+ int ret = ERROR;
+
+ pstate->ht_sndlen = 0;
+
+ nvdbg("[%d] sending file '%s'\n", pstate->ht_sockfd, pstate->ht_filename);
+
+#ifdef CONFIG_NETUTILS_HTTPD_CGIPATH
+ {
+ httpd_cgifunction f;
+
+ f = httpd_cgi(pstate->ht_filename);
+ if (f != NULL)
+ {
+ f(pstate, pstate->ht_filename);
+
+ ret = OK;
+ goto done;
+ }
+ }
+#endif
+
+ if (httpd_open(pstate->ht_filename, &pstate->ht_file) != OK)
+ {
+ ndbg("[%d] '%s' not found\n", pstate->ht_sockfd, pstate->ht_filename);
+ memcpy(pstate->ht_filename, g_http404path, strlen(g_http404path));
+ if (httpd_open(g_http404path, &pstate->ht_file) != OK)
+ {
+ return ERROR;
+ }
+
+ if (send_headers(pstate, g_httpheader404, strlen(g_httpheader404)) == OK)
+ {
+#ifdef CONFIG_NETUTILS_HTTPD_SENDFILE
+ ret = httpd_sendfile_send(pstate->ht_sockfd, &pstate->ht_file);
+#else
+ ret = httpd_addchunk(pstate, pstate->ht_file.data, pstate->ht_file.len);
+#endif
+ }
+ }
+ else
+ {
+ if (send_headers(pstate, g_httpheader200, strlen(g_httpheader200)) == OK)
+ {
+ if (httpd_flush(pstate) < 0)
+ {
+ ret = ERROR;
+ }
+ else
+ {
+#ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE
+ ptr = strchr(pstate->ht_filename, ISO_period);
+ if (ptr != NULL &&
+ strncmp(ptr, g_httpextensionshtml, strlen(g_httpextensionshtml)) == 0)
+ {
+ ret = handle_script(pstate);
+ }
+ else
+#endif
+ {
+#ifdef CONFIG_NETUTILS_HTTPD_SENDFILE
+ ret = httpd_sendfile_send(pstate->ht_sockfd, &pstate->ht_file);
+#else
+ ret = httpd_addchunk(pstate, pstate->ht_file.data, pstate->ht_file.len);
+#endif
+ }
+ }
+ }
+ }
+
+ (void)httpd_close(&pstate->ht_file);
+
+done:
+
+ /* Send anything remaining in the buffer */
+
+ if (ret == OK && pstate->ht_sndlen > 0)
+ {
+ if (httpd_flush(pstate) < 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;
+ }
+ else if (recvlen == 0)
+ {
+ ndbg("[%d] connection lost\n", pstate->ht_sockfd);
+ 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)
+{
+#if !defined(CONFIG_NETUTILS_HTTPD_MMAP) && !defined(CONFIG_NETUTILS_HTTPD_SENDFILE)
+ httpd_fs_init();
+#endif
+}
diff --git a/apps/netutils/webserver/httpd.h b/apps/netutils/webserver/httpd.h
new file mode 100644
index 000000000..dbe3d0e20
--- /dev/null
+++ b/apps/netutils/webserver/httpd.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+ * netutils/webserver/httpd.h
+ *
+ * Copyright (C) 2007, 2009, 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <nuttx/net/uip/uipopt.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* 'file' must be allocated by caller and will be filled in by the function. */
+
+#if defined(CONFIG_NETUTILS_HTTPD_SENDFILE)
+
+int httpd_sendfile_open(const char *name, struct httpd_fs_file *file);
+int httpd_sendfile_close(struct httpd_fs_file *file);
+int httpd_sendfile_send(int outfd, struct httpd_fs_file *file);
+
+#elif defined(CONFIG_NETUTILS_HTTPD_MMAP)
+
+int httpd_mmap_open(const char *name, struct httpd_fs_file *file);
+int httpd_mmap_close(struct httpd_fs_file *file);
+
+#else
+
+int httpd_fs_open(const char *name, struct httpd_fs_file *file);
+void httpd_fs_init(void);
+
+#endif
+
+#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..fa11f12ec
--- /dev/null
+++ b/apps/netutils/webserver/httpd_cgi.c
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * 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 <string.h>
+
+#include <apps/netutils/httpd.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+struct httpd_cgi_call *cgi_calls = NULL;
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void httpd_cgi_register(struct httpd_cgi_call *cgi_call)
+{
+ if (cgi_calls == NULL)
+ {
+ cgi_calls = cgi_call;
+ }
+ else
+ {
+ cgi_call->next = cgi_calls;
+ cgi_calls = cgi_call;
+ }
+}
+
+httpd_cgifunction httpd_cgi(char *name)
+{
+ struct httpd_cgi_call *cgi_call = cgi_calls;
+ while (cgi_call != NULL)
+ {
+ if (strncmp(cgi_call->name, name, strlen(cgi_call->name)) == 0)
+ {
+ return cgi_call->function;
+ }
+
+ cgi_call = cgi_call->next;
+ }
+
+ return NULL;
+}
diff --git a/apps/netutils/webserver/httpd_cgi.h b/apps/netutils/webserver/httpd_cgi.h
new file mode 100644
index 000000000..546a909f0
--- /dev/null
+++ b/apps/netutils/webserver/httpd_cgi.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+ * netutils/webserver/httpd_cgi.h
+ *
+ * Copyright (C) 2007, 2009, 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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_CGI_H
+#define _NETUTILS_WEBSERVER_HTTPD_CGI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <apps/netutils/httpd.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+httpd_cgifunction httpd_cgi(char *name);
+
+#endif /* _NETUTILS_WEBSERVER_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..b8eae3063
--- /dev/null
+++ b/apps/netutils/webserver/httpd_fs.c
@@ -0,0 +1,153 @@
+/****************************************************************************
+ * netutils/webserver/httpd_fs.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <stdlib.h>
+
+#include <apps/netutils/httpd.h>
+
+#include "httpd.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_NETUTILS_HTTPDFSSTATS
+static uint16_t *count;
+#endif
+
+/****************************************************************************
+ * 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)
+{
+#ifdef CONFIG_NETUTILS_HTTPDFSSTATS
+ uint16_t i = 0;
+#endif
+ struct httpd_fsdata_file_noconst *f;
+
+ for(f = (struct httpd_fsdata_file_noconst *)g_httpdfs_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;
+#ifdef CONFIG_NETUTILS_HTTPDFSSTATS
+ ++count[i];
+#endif
+ return 1;
+ }
+#ifdef CONFIG_NETUTILS_HTTPDFSSTATS
+ ++i;
+#endif
+ }
+ return 0;
+}
+
+void httpd_fs_init(void)
+{
+#ifdef CONFIG_NETUTILS_HTTPDFSSTATS
+ uint16_t i;
+
+ count = (uint16_t*)malloc(g_httpd_numfiles * sizeof(uint16_t));
+
+ for(i = 0; i < g_httpd_numfiles; i++)
+ {
+ count[i] = 0;
+ }
+#endif
+}
+
+#ifdef 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 *)g_httpdfs_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_mmap.c b/apps/netutils/webserver/httpd_mmap.c
new file mode 100644
index 000000000..9777df3b3
--- /dev/null
+++ b/apps/netutils/webserver/httpd_mmap.c
@@ -0,0 +1,143 @@
+/****************************************************************************
+ * netutils/webserver/httpd_mmap.c
+ *
+ * Copyright (C) 2012 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 Header Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <apps/netutils/httpd.h>
+
+#include "httpd.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int httpd_mmap_open(const char *name, struct httpd_fs_file *file)
+{
+ char path[PATH_MAX];
+ struct stat st;
+
+ if (sizeof path < snprintf(path, sizeof path, "%s%s",
+ CONFIG_NETUTILS_HTTPD_PATH, name))
+ {
+ errno = ENAMETOOLONG;
+ return ERROR;
+ }
+
+ /* XXX: awaiting fstat to avoid a race */
+
+ if (-1 == stat(path, &st))
+ {
+ return ERROR;
+ }
+
+ if (st.st_size > INT_MAX)
+ {
+ errno = EFBIG;
+ return ERROR;
+ }
+
+ file->len = (int) st.st_size;
+
+ /* SUS3: "If len is zero, mmap() shall fail and no mapping shall be established." */
+
+ if (st.st_size == 0)
+ {
+ return OK;
+ }
+
+ file->fd = open(path, O_RDONLY);
+ if (file->fd == -1)
+ {
+ return ERROR;
+ }
+
+ file->data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED | MAP_FILE, file->fd, 0);
+ if (file->data == MAP_FAILED)
+ {
+ (void) close(file->fd);
+ return ERROR;
+ }
+
+ return OK;
+}
+
+int httpd_mmap_close(struct httpd_fs_file *file)
+{
+ if (file->len == 0)
+ {
+ return OK;
+ }
+
+#ifdef CONFIG_FS_RAMMAP
+ if (-1 == munmap(file->data, file->len))
+ {
+ return ERROR;
+ }
+#endif
+
+ if (-1 == close(file->fd))
+ {
+ return ERROR;
+ }
+
+ return OK;
+}
diff --git a/apps/netutils/webserver/httpd_sendfile.c b/apps/netutils/webserver/httpd_sendfile.c
new file mode 100644
index 000000000..6a6ec24ab
--- /dev/null
+++ b/apps/netutils/webserver/httpd_sendfile.c
@@ -0,0 +1,128 @@
+/****************************************************************************
+ * netutils/webserver/httpd_mmap.c
+ *
+ * Copyright (C) 2012 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 Header Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sendfile.h>
+
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <apps/netutils/httpd.h>
+
+#include "httpd.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int httpd_sendfile_open(const char *name, struct httpd_fs_file *file)
+{
+ char path[PATH_MAX];
+ struct stat st;
+
+ if (sizeof path < snprintf(path, sizeof path, "%s%s",
+ CONFIG_NETUTILS_HTTPD_PATH, name))
+ {
+ errno = ENAMETOOLONG;
+ return ERROR;
+ }
+
+ /* XXX: awaiting fstat to avoid a race */
+
+ if (-1 == stat(path, &st))
+ {
+ return ERROR;
+ }
+
+ if (st.st_size > INT_MAX || st.st_size > SIZE_MAX)
+ {
+ errno = EFBIG;
+ return ERROR;
+ }
+
+ file->len = (int) st.st_size;
+
+ file->fd = open(path, O_RDONLY);
+ if (file->fd == -1)
+ {
+ return ERROR;
+ }
+
+ return OK;
+}
+
+int httpd_sendfile_close(struct httpd_fs_file *file)
+{
+ if (-1 == close(file->fd))
+ {
+ return ERROR;
+ }
+
+ return OK;
+}
+
+int httpd_sendfile_send(int outfd, struct httpd_fs_file *file)
+{
+ if (-1 == sendfile(outfd, file->fd, 0, file->len))
+ {
+ return ERROR;
+ }
+
+ return OK;
+}
+
diff --git a/apps/netutils/xmlrpc/Kconfig b/apps/netutils/xmlrpc/Kconfig
new file mode 100644
index 000000000..6765bda07
--- /dev/null
+++ b/apps/netutils/xmlrpc/Kconfig
@@ -0,0 +1,23 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_XMLRPC
+ bool "XML RPC library"
+ default n
+ depends on NET_TCP
+ select NETUTILS_UIPLIB
+ ---help---
+ Enables the Embeddable Lightweight XML-RPC Server discussed at
+ http://www.drdobbs.com/web-development/an-embeddable-lightweight-xml-rpc-server/184405364
+
+if NETUTILS_XMLRPC
+
+config XMLRPC_STRINGSIZE
+ int "Maximum string length"
+ default 64
+ ---help---
+ Maximum string length for method names and XML RPC string values.
+
+endif
diff --git a/apps/netutils/xmlrpc/Makefile b/apps/netutils/xmlrpc/Makefile
new file mode 100644
index 000000000..903506f46
--- /dev/null
+++ b/apps/netutils/xmlrpc/Makefile
@@ -0,0 +1,99 @@
+############################################################################
+# apps/netutils/xmlrpc/Makefile
+#
+# Copyright (C) 2012 Max Holtzberg. All rights reserved.
+# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+#
+# Authors: Max Holtzberg <mh@uvc.de>
+# 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
+
+
+ASRCS =
+CSRCS =
+
+ifeq ($(CONFIG_NET_TCP),y)
+CSRCS += xmlparser.c response.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/xmlrpc/response.c b/apps/netutils/xmlrpc/response.c
new file mode 100644
index 000000000..2ae7414a7
--- /dev/null
+++ b/apps/netutils/xmlrpc/response.c
@@ -0,0 +1,287 @@
+/****************************************************************************
+ * apps/netutils/xmlrpc/response.c
+ *
+ * Copyright (C) 2012 Max Holtzberg. All rights reserved.
+ * Author: Max Holtzberg <mh@uvc.de>
+ *
+ * Based on the embeddable lightweight XML-RPC server code discussed
+ * in the article at: http://www.drdobbs.com/web-development/\
+ * an-embeddable-lightweight-xml-rpc-server/184405364
+ *
+ * Copyright (c) 2002 Cogito LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, is hereby granted without fee provided
+ * that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright 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 Cogito LLC nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COGITO LLC AND CONTRIBUTERS 'AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COGITO LLC
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARAY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************/
+
+/*
+ * Lightweight Embedded XML-RPC Server Response Generator
+ *
+ * mtj@cogitollc.com
+ *
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <apps/netutils/xmlrpc.h>
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int xmlrpc_insertlength(struct xmlrpc_s * xmlcall)
+{
+ int len, digit, xdigit = 1000, i = 0;
+ char *temp;
+
+ temp = strstr(xmlcall->response, "<?xml");
+ len = strlen(temp);
+
+ temp = strstr(xmlcall->response, "xyza");
+
+ do
+ {
+ digit = (len / xdigit);
+ len -= (digit * xdigit);
+ xdigit /= 10;
+
+ if ((digit == 0) && (xdigit > 1))
+ temp[i++] = ' ';
+ else
+ temp[i++] = (0x30 + digit);
+ }
+ while (i < 4);
+
+ return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int xmlrpc_getinteger(struct xmlrpc_s * xmlcall, int *arg)
+{
+ if ((xmlcall == NULL) || (arg == NULL))
+ {
+ return XMLRPC_INTERNAL_ERROR;
+ }
+
+ if ((xmlcall->arg < xmlcall->argsize) &&
+ (xmlcall->args[xmlcall->arg] == 'i'))
+ {
+ *arg = xmlcall->arguments[xmlcall->arg++].u.i;
+ return 0;
+ }
+
+ return XMLRPC_UNEXPECTED_INTEGER_ARG;
+}
+
+int xmlrpc_getbool(struct xmlrpc_s * xmlcall, int *arg)
+{
+ if ((xmlcall == NULL) || (arg == NULL))
+ {
+ return XMLRPC_INTERNAL_ERROR;
+ }
+
+ if ((xmlcall->arg < xmlcall->argsize) &&
+ (xmlcall->args[xmlcall->arg] == 'b'))
+ {
+ *arg = xmlcall->arguments[xmlcall->arg++].u.i;
+ return 0;
+ }
+
+ return XMLRPC_UNEXPECTED_BOOLEAN_ARG;
+}
+
+int xmlrpc_getdouble(struct xmlrpc_s * xmlcall, double *arg)
+{
+ if ((xmlcall == NULL) || (arg == NULL))
+ {
+ return XMLRPC_INTERNAL_ERROR;
+ }
+
+ if ((xmlcall->arg < xmlcall->argsize) &&
+ (xmlcall->args[xmlcall->arg] == 'd'))
+ {
+ *arg = xmlcall->arguments[xmlcall->arg++].u.d;
+ return 0;
+ }
+
+ return XMLRPC_UNEXPECTED_DOUBLE_ARG;
+}
+
+int xmlrpc_getstring(struct xmlrpc_s* xmlcall, char *arg)
+{
+ if ((xmlcall == NULL) || (arg == NULL))
+ {
+ return XMLRPC_INTERNAL_ERROR;
+ }
+
+ if ((xmlcall->arg < xmlcall->argsize) &&
+ (xmlcall->args[xmlcall->arg] == 's'))
+ {
+ strcpy(arg, xmlcall->arguments[xmlcall->arg++].u.string);
+ return 0;
+ }
+
+ return XMLRPC_UNEXPECTED_STRING_ARG;
+}
+
+int xmlrpc_buildresponse(struct xmlrpc_s* xmlcall, char *args, ...)
+{
+ va_list argp;
+ int i, ret = 0, index = 0, close = 0;
+ double d;
+ char *s;
+ int isStruct = 0;
+
+ if ((xmlcall == NULL) || (args == NULL))
+ {
+ return -1;
+ }
+
+ strcpy(xmlcall->response, "HTTP/1.1 200 OK\n"
+ "Connection: close\n"
+ "Content-length: xyza\n"
+ "Content-Type: text/xml\n"
+ "Server: Lightweight XMLRPC\n\n"
+ "<?xml version=\"1.0\"?>\n" "<methodResponse>\n");
+
+ if (xmlcall->error)
+ {
+ strcat(&xmlcall->response[strlen(xmlcall->response)], " <fault>\n");
+ }
+ else
+ {
+ strcat(&xmlcall->response[strlen(xmlcall->response)],
+ " <params><param>\n");
+ }
+
+ va_start(argp, args);
+
+ while (args[index])
+ {
+ if (isStruct)
+ {
+ if ((args[index] != '{') && (args[index] != '}'))
+ {
+ sprintf(&xmlcall->response[strlen(xmlcall->response)],
+ " <member>\n");
+ sprintf(&xmlcall->response[strlen(xmlcall->response)],
+ " <name>%s</name>\n", va_arg(argp, char *));
+ close = 1;
+ }
+ }
+
+ switch (args[index])
+ {
+ case '{':
+ sprintf(&xmlcall->response[strlen(xmlcall->response)],
+ " <value><struct>\n");
+ isStruct = 1;
+ break;
+
+ case '}':
+ sprintf(&xmlcall->response[strlen(xmlcall->response)],
+ " </struct></value>\n");
+ isStruct = 0;
+ break;
+
+ case 'i':
+ i = va_arg(argp, int);
+ sprintf(&xmlcall->response[strlen(xmlcall->response)],
+ " <value><int>%d</int></value>\r\n", i);
+ break;
+
+ case 'b':
+ i = va_arg(argp, int);
+ sprintf(&xmlcall->response[strlen(xmlcall->response)],
+ " <value><boolean>%d</boolean></value>\r\n", i);
+ break;
+
+ case 'd':
+ d = va_arg(argp, double);
+ sprintf(&xmlcall->response[strlen(xmlcall->response)],
+ " <value><double>%f</double></value>\r\n", d);
+ break;
+
+ case 's':
+ s = va_arg(argp, char *);
+ sprintf(&xmlcall->response[strlen(xmlcall->response)],
+ " <value><string>%s</string></value>\r\n", s);
+ break;
+
+ default:
+ return (XMLRPC_BAD_RESPONSE_ARG);
+ break;
+
+ }
+
+ if (close)
+ {
+ sprintf(&xmlcall->response[strlen(xmlcall->response)],
+ " </member>\n");
+ close = 0;
+ }
+
+ index++;
+ }
+
+ va_end(argp);
+
+ if (xmlcall->error)
+ {
+ strcat(&xmlcall->response[strlen(xmlcall->response)], " </fault>\r\n");
+ }
+ else
+ {
+ strcat(&xmlcall->response[strlen(xmlcall->response)],
+ " </param></params>\r\n");
+ }
+
+ if (ret == 0)
+ {
+ strcat(&xmlcall->response[strlen(xmlcall->response)],
+ "</methodResponse>\r\n");
+
+ xmlrpc_insertlength(xmlcall);
+ }
+ else
+ {
+ xmlcall->response[0] = 0;
+ }
+
+ return ret;
+}
diff --git a/apps/netutils/xmlrpc/xmlparser.c b/apps/netutils/xmlrpc/xmlparser.c
new file mode 100644
index 000000000..72387a08e
--- /dev/null
+++ b/apps/netutils/xmlrpc/xmlparser.c
@@ -0,0 +1,416 @@
+/****************************************************************************
+ * apps/netutils/xmlrpc/xmlparser.c
+ *
+ * Copyright (C) 2012 Max Holtzberg. All rights reserved.
+ * Author: Max Holtzberg <mh@uvc.de>
+ *
+ * Based on the embeddable lightweight XML-RPC server code discussed
+ * in the article at: http://www.drdobbs.com/web-development/\
+ * an-embeddable-lightweight-xml-rpc-server/184405364
+ *
+ * Copyright (c) 2002 Cogito LLC. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, is hereby granted without fee provided
+ * that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright 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 Cogito LLC nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY COGITO LLC AND CONTRIBUTERS 'AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COGITO LLC
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARAY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************/
+
+/*
+ * Lightweight Embedded XML-RPC Server XML Parser
+ *
+ * mtj@cogitollc.com
+ *
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <apps/netutils/xmlrpc.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define TAG 0
+#define VALUE 1
+#define DONE 2
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct xmlrpc_s g_xmlcall;
+static char g_data[CONFIG_XMLRPC_STRINGSIZE+1];
+static struct xmlrpc_entry_s *g_entries = NULL;
+
+static const char *errorStrings[] =
+{
+ /* 0 */ "Internal error (unknown)",
+ /* 1 */ "Parse Error...",
+ /* 2 */ "Function not found...",
+ /* 3 */ "Unexpected Integer Argument...",
+ /* 4 */ "Unexpected Boolean Argument...",
+ /* 5 */ "Unexpected Double Argument...",
+ /* 6 */ "Unexpected String Argument...",
+ /* 7 */ "Bad Response Argument..."
+};
+
+#define MAX_ERROR_CODE (sizeof(errorStrings)/sizeof(char *))
+
+struct parsebuf_s
+{
+ char *buf;
+ int len;
+ int index;
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int xmlrpc_call(struct xmlrpc_s * call)
+{
+ int ret = XMLRPC_NO_SUCH_FUNCTION;
+ struct xmlrpc_entry_s *entry = g_entries;
+
+ while (entry != NULL)
+ {
+ if (strcmp(call->name, entry->name) == 0)
+ {
+ ret = entry->func(call);
+ break;
+ }
+ else
+ {
+ entry = entry->next;
+ }
+ }
+
+ return ret;
+}
+
+static int xmlrpc_getelement(struct parsebuf_s * pbuf, char *data, int dataSize)
+{
+ int j = 0;
+ int ret = XMLRPC_NO_ERROR;
+
+ while (!isprint(pbuf->buf[pbuf->index]))
+ {
+ pbuf->index++;
+ }
+
+ if (pbuf->index >= pbuf->len)
+ {
+ return DONE;
+ }
+
+ if (pbuf->buf[pbuf->index] == '<')
+ {
+ ret = TAG;
+ }
+ else
+ {
+ ret = VALUE;
+ }
+
+ data[j++] = pbuf->buf[pbuf->index++];
+
+ while (j < dataSize)
+ {
+ if (pbuf->buf[pbuf->index] == '>')
+ {
+ data[j++] = pbuf->buf[pbuf->index++];
+ break;
+ }
+ else if ((pbuf->buf[pbuf->index] == '\n') ||
+ (pbuf->buf[pbuf->index] == '<'))
+ {
+ break;
+ }
+ else
+ {
+ data[j++] = pbuf->buf[pbuf->index++];
+ if (j >= dataSize)
+ ret = XMLRPC_PARSE_ERROR;
+ }
+ }
+
+ data[j] = 0;
+ return ret;
+}
+
+static int xmlrpc_parseparam(struct parsebuf_s * pbuf)
+{
+ int type;
+
+ /* Next, we need a <value> tag */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if (!((type == TAG) && (!strncmp(g_data, "<value>", 7))))
+ {
+ return XMLRPC_PARSE_ERROR;
+ }
+
+ /* Now we get a variable tag, the type of the value */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if (type != TAG)
+ {
+ return XMLRPC_PARSE_ERROR;
+ }
+
+ if (!strncmp(g_data, "<i4>", 4))
+ {
+ g_xmlcall.args[g_xmlcall.argsize] = 'i';
+ }
+ else if (!strncmp(g_data, "<int>", 5))
+ {
+ g_xmlcall.args[g_xmlcall.argsize] = 'i';
+ }
+ else if (!strncmp(g_data, "<boolean>", 9))
+ {
+ g_xmlcall.args[g_xmlcall.argsize] = 'b';
+ }
+ else if (!strncmp(g_data, "<double>", 8))
+ {
+ g_xmlcall.args[g_xmlcall.argsize] = 'd';
+ }
+ else if (!strncmp(g_data, "<string>", 8))
+ {
+ g_xmlcall.args[g_xmlcall.argsize] = 's';
+ }
+ else
+ {
+ return XMLRPC_PARSE_ERROR;
+ }
+
+ /* Now, parse the actual value */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if (type != VALUE)
+ {
+ return XMLRPC_PARSE_ERROR;
+ }
+
+ switch (g_xmlcall.args[g_xmlcall.argsize])
+ {
+ case 'i':
+ case 'b':
+ g_xmlcall.arguments[g_xmlcall.argsize].u.i = atoi(g_data);
+ break;
+ case 'd':
+ g_xmlcall.arguments[g_xmlcall.argsize].u.d = atof(g_data);
+ break;
+ case 's':
+ strcpy(g_xmlcall.arguments[g_xmlcall.argsize].u.string, g_data);
+ break;
+ default:
+ return XMLRPC_PARSE_ERROR;
+ }
+
+ g_xmlcall.argsize++;
+
+ /* Now we close out the tag, starting with the type */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if (!((type == TAG) && (!strncmp(g_data, "</", 2))))
+ {
+ return XMLRPC_PARSE_ERROR;
+ }
+
+ /* Next, look for the </value> close */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if (!((type == TAG) && (!strncmp(g_data, "</value>", 8))))
+ {
+ return XMLRPC_PARSE_ERROR;
+ }
+
+ /* Finally, close out the </param> tag */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if (!((type == TAG) && (!strncmp(g_data, "</param>", 8))))
+ {
+ return XMLRPC_PARSE_ERROR;
+ }
+
+ return XMLRPC_NO_ERROR;
+}
+
+static int xmlrpc_parseparams(struct parsebuf_s * pbuf)
+{
+ int type, ret = XMLRPC_PARSE_ERROR;
+
+ /* First, look for the params tag */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if ((type == TAG) && (!strncmp(g_data, "<params>", 8)))
+ {
+ while (1)
+ {
+ /* Get next tag */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if ((type == TAG) && (!strncmp(g_data, "<param>", 7)))
+ {
+ ret = xmlrpc_parseparam(pbuf);
+ }
+ else if ((type == TAG) && (!strncmp(g_data, "</params>", 9)))
+ {
+ return XMLRPC_NO_ERROR;
+ }
+ else
+ {
+ return XMLRPC_PARSE_ERROR;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int xmlrpc_parsemethod(struct parsebuf_s * pbuf)
+{
+ int type, ret = XMLRPC_PARSE_ERROR;
+
+ bzero((void *)&g_xmlcall, sizeof(struct xmlrpc_s));
+
+ /* Look for the methodName tag */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if ((type == TAG) && (!strncmp(g_data, "<methodName>", 12)))
+ {
+ /* Get the method name for the call */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if (type == VALUE)
+ {
+ /* Save the method name */
+
+ strcpy(g_xmlcall.name, g_data);
+
+ /* Find the closing /methodCall */
+
+ type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if ((type == TAG) && (!strncmp(g_data, "</methodName>", 13)))
+ {
+ /* Now, it's time to parse the parameters */
+
+ ret = xmlrpc_parseparams(pbuf);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void xmlrpc_sendfault(int fault)
+{
+ fault = -fault;
+ if (fault >= MAX_ERROR_CODE)
+ {
+ fault = 0;
+ }
+
+ xmlrpc_buildresponse(&g_xmlcall, "{is}",
+ "faultCode", fault, "faultString", errorStrings[fault]);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int xmlrpc_parse(int sock, char *buffer)
+{
+ struct parsebuf_s pbuf;
+ int type;
+ int ret = XMLRPC_PARSE_ERROR;
+
+ pbuf.buf = buffer;
+ pbuf.len = strlen(buffer);
+ pbuf.index = 0;
+
+ /* Parse the xml header tag */
+
+ type = xmlrpc_getelement(&pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if ((type == TAG) && (!strncmp(g_data, "<?xml", 5)))
+ {
+ type = xmlrpc_getelement(&pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if ((type == TAG) && (!strncmp(g_data, "<methodCall>", 12)))
+ {
+ /* Parse the remaining tags within the methodCall tag */
+
+ xmlrpc_parsemethod(&pbuf);
+
+ /* Check for the closing /methodCall */
+
+ type = xmlrpc_getelement(&pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE);
+ if ((type == TAG) && (!strncmp(g_data, "</methodCall>", 13)))
+ {
+ /* Successful parse, try to call a user function */
+
+ ret = xmlrpc_call(&g_xmlcall);
+ }
+ }
+ }
+
+ if (ret == 0)
+ {
+ write(sock, g_xmlcall.response, strlen(g_xmlcall.response));
+ }
+ else
+ {
+ /* Send fault response */
+
+ g_xmlcall.error = 1;
+ xmlrpc_sendfault(ret);
+ write(sock, g_xmlcall.response, strlen(g_xmlcall.response));
+ }
+
+ return ret;
+}
+
+void xmlrpc_register(struct xmlrpc_entry_s *entry)
+{
+ if (g_entries == NULL)
+ {
+ g_entries = entry;
+ entry->next = NULL;
+ }
+ else
+ {
+ entry->next = g_entries;
+ g_entries = entry;
+ }
+}
diff --git a/apps/nshlib/Kconfig b/apps/nshlib/Kconfig
new file mode 100644
index 000000000..c0f7d6a92
--- /dev/null
+++ b/apps/nshlib/Kconfig
@@ -0,0 +1,494 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NSH_LIBRARY
+ bool "NSH Library"
+ default n
+ select SYSTEM_READLINE
+ ---help---
+ Build the NSH support library. This is used, for example, by examples/nsh
+ in order to implement the full NuttShell (NSH).
+
+if NSH_LIBRARY
+config NSH_BUILTIN_APPS
+ bool "Enable built-in applications"
+ default y
+ depends on NAMEDAPP
+ ---help---
+ Support external registered, "named" applications that can be
+ executed from the NSH command line (see apps/README.txt for
+ more information). This options requires support for named applications
+ (NAMEDAPP).
+
+menu "Disable Individual commands"
+config NSH_DISABLE_CAT
+ bool "Disable cat"
+ default n
+config NSH_DISABLE_CD
+ bool "Disable cd"
+ default n
+config NSH_DISABLE_CP
+ bool "Disable cp"
+ default n
+config NSH_DISABLE_DD
+ bool "Disable dd"
+ default n
+config NSH_DISABLE_ECHO
+ bool "Disable echo"
+ default n
+config NSH_DISABLE_EXEC
+ bool "Disable exec"
+ default n
+config NSH_DISABLE_EXIT
+ bool "Disable exit"
+ default n
+config NSH_DISABLE_FREE
+ bool "Disable free"
+ default n
+config NSH_DISABLE_GET
+ bool "Disable get"
+ default n
+config NSH_DISABLE_HELP
+ bool "Disable help"
+ default n
+config NSH_DISABLE_IFCONFIG
+ bool "Disable ifconfig"
+ default n
+config NSH_DISABLE_KILL
+ bool "Disable kill"
+ default n
+config NSH_DISABLE_LOSETUP
+ bool "Disable losetup"
+ default n
+config NSH_DISABLE_LS
+ bool "Disable ls"
+ default n
+config NSH_DISABLE_MB
+ bool "Disable mb"
+ default n
+config NSH_DISABLE_MKDIR
+ bool "Disable mkdir"
+ default n
+config NSH_DISABLE_MKFATFS
+ bool "Disable mkfatfs"
+ default n
+config NSH_DISABLE_MKFIFO
+ bool "Disable mkfifo"
+ default n
+config NSH_DISABLE_MKRD
+ bool "Disable mkrd"
+ default n
+config NSH_DISABLE_MH
+ bool "Disable mh"
+ default n
+config NSH_DISABLE_MOUNT
+ bool "Disable mount"
+ default n
+config NSH_DISABLE_MW
+ bool "Disable mw"
+ default n
+config NSH_DISABLE_NSFMOUNT
+ bool "Disable nfsmount"
+ default n
+config NSH_DISABLE_PS
+ bool "Disable ps"
+ default n
+config NSH_DISABLE_PING
+ bool "Disable ping"
+ default n
+config NSH_DISABLE_PUT
+ bool "Disable put"
+ default n
+config NSH_DISABLE_PWD
+ bool "Disable pwd"
+ default n
+config NSH_DISABLE_RM
+ bool "Disable rm"
+ default n
+config NSH_DISABLE_RMDIR
+ bool "Disable rmdir"
+ default n
+config NSH_DISABLE_SET
+ bool "Disable set"
+ default n
+config NSH_DISABLE_SH
+ bool "Disable sh"
+ default n
+config NSH_DISABLE_SLEEP
+ bool "Disable sleep"
+ default n
+config NSH_DISABLE_TEST
+ bool "Disable test"
+ default n
+config NSH_DISABLE_UMOUNT
+ bool "Disable umount"
+ default n
+config NSH_DISABLE_UNSET
+ bool "Disable unset"
+ default n
+config NSH_DISABLE_USLEEP
+ bool "Disable usleep"
+ default n
+config NSH_DISABLE_WGET
+ bool "Disable wget"
+ default n
+config NSH_DISABLE_XD
+ bool "Disable xd"
+ default n
+endmenu
+
+config NSH_FILEIOSIZE
+ int "NSH I/O buffer size"
+ default 1024
+ ---help---
+ Size of a static I/O buffer used for file access (ignored if
+ there is no filesystem). Default is 1024.
+
+config NSH_STRERROR
+ bool "Use strerror()"
+ default n
+ depends on LIBC_STRERROR
+ ---help---
+ strerror(errno) makes more readable output but strerror() is
+ very large and will not be used unless this setting is 'y'
+ This setting depends upon the strerror() having been enabled
+ with LIBC_STRERROR.
+
+config NSH_LINELEN
+ int "Max command line length"
+ default 80
+ ---help---
+ The maximum length of one command line and of one output line.
+ Default: 80
+
+config NSH_NESTDEPTH
+ int "Maximum command nesting"
+ default 3
+ ---help---
+ The maximum number of nested if-then[-else]-fi sequences that
+ are permissable. Default: 3
+
+config NSH_DISABLESCRIPT
+ bool "Disable script support"
+ default n
+ ---help---
+ 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
+ bool "Disable background commands"
+ default n
+ ---help---
+ 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
+ int "MMC/SD minor device number"
+ default 0
+ ---help---
+ 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
+ bool "Support ROMFS start-up script"
+ default n
+ depends on FS_ROMFS
+ ---help---
+ 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.
+
+endif
+
+if NSH_ROMFSETC
+config NSH_ROMFSMOUNTPT
+ string "ROMFS mount point"
+ default "/etc"
+ ---help---
+ 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
+ string "Relative path to startup script"
+ default "init.d/rcS"
+ ---help---
+ 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
+ int "ROMFS block device minor number"
+ default 0
+ ---help---
+ This is the minor number of the ROMFS block device. The default is
+ '0' corresponding to /dev/ram0.
+
+config NSH_ROMFSSECTSIZE
+ int "ROMFS sector size"
+ default 64
+ ---help---
+ 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.
+
+config NSH_FATDEVNO
+ int "FAT block device minor number"
+ default 0
+ depends on FS_FAT
+ ---help---
+ When the default rcS file used when NSH_ROMFSETC is selected, it
+ will mount a FAT FS under /tmp. This is the minor number of the FAT
+ FS block device. The default is '1' corresponding to /dev/ram1.
+
+config NSH_FATSECTSIZE
+ int "FAT sector size"
+ default 512
+ depends on FS_FAT
+ ---help---
+ When the default rcS file used when NSH_ROMFSETC is selected, it
+ will mount a FAT FS under /tmp. This is the sector size use with the
+ FAT FS. Default is 512.
+
+config NSH_FATNSECTORS
+ int "FAT number of sectors"
+ default 1024
+ depends on FS_FAT
+ ---help---
+ When the default rcS file used when NSH_ROMFSETC is selected, it
+ will mount a FAT FS under /tmp. This is the number of sectors to use
+ with the FAT FS. Defualt is 1024. The amount of memory used by the
+ FAT FS will be NSH_FATSECTSIZE * NSH_FATNSECTORS bytes.
+
+config NSH_FATMOUNTPT
+ string "FAT mount point"
+ default "/tmp"
+ depends on FS_FAT
+ ---help---
+ When the default rcS file used when NSH_ROMFSETC is selected, it
+ will mount a FAT FS under /tmp. This is the location where the FAT
+ FS will be mounted. Default is "/tmp".
+
+endif
+
+if NSH_LIBRARY
+config NSH_CONSOLE
+ bool "Use console"
+ default y
+ ---help---
+ If NSH_CONSOLE is set to 'y', then a character driver
+ console front-end is selected (/dev/console).
+
+ Normally, the serial console device is a UART and RS-232
+ interface. However, if CONFIG_USBDEV is defined, then a USB
+ serial device may, instead, be used if the one of
+ the following are defined:
+
+ CONFIG_PL2303 and CONFIG_PL2303_CONSOLE - Sets up the
+ Prolifics PL2303 emulation as a console device at /dev/console.
+
+ CONFIG_CDCACM and CONFIG_CDCACM_CONSOLE - Sets up the
+ CDC/ACM serial device as a console device at dev/console.
+
+ CONFIG_NSH_USBCONSOLE and CONFIG_NSH_USBCONDEV - Sets up the
+ some other USB serial device as the NSH console (not necessarily
+ dev/console).
+
+config NSH_USBCONSOLE
+ bool "Use a USB console"
+ default n
+ depends on NSH_CONSOLE && USBDEV
+ ---help---
+ If defined, then the an arbitrary USB device may be used
+ to as the NSH console. In this case, CONFIG_NSH_USBCONDEV
+ must be defined to indicate which USB device to use as
+ the console.
+
+config NSH_USBCONDEV
+ string "USB console device"
+ default "/dev/ttyACM0"
+ depends on NSH_USBCONSOLE
+ ---help---
+ If CONFIG_NSH_USBCONSOLE is set to 'y', then CONFIG_NSH_USBCONDEV
+ must also be set to select the USB device used to support
+ the NSH console. This should be set to the quoted name of a
+ readable/write-able USB driver such as:
+ CONFIG_NSH_USBCONDEV="/dev/ttyACM0".
+
+config UBSDEV_MINOR
+ int "USB console device minor number"
+ default 0
+ depends on NSH_USBCONSOLE
+ ---help---
+ If there are more than one USB devices, then a USB device
+ minor number may also need to be provided. Default: 0
+
+menu "USB Trace Support"
+ depends on USBDEV && (DEBUG || USBDEV_TRACE)
+
+config NSH_USBDEV_TRACEINIT
+ bool "Show initialization events"
+ default n
+ ---help---
+ Show initialization events
+
+config NSH_USBDEV_TRACECLASS
+ bool "Show class driver events"
+ default n
+ ---help---
+ Show class driver events
+
+config NSH_USBDEV_TRACETRANSFERS
+ bool "Show data transfer events"
+ default n
+ ---help---
+ Show data transfer events
+
+config NSH_USBDEV_TRACECONTROLLER
+ bool "Show controller events"
+ default n
+ ---help---
+ Show controller events
+
+config NSH_USBDEV_TRACEINTERRUPTS
+ bool "Show interrupt-related events"
+ default n
+ ---help---
+ Show interrupt-related events
+
+endmenu
+
+config NSH_CONDEV
+ bool "Default console device"
+ default "/dev/console"
+ depends on NSH_CONSOLE && !NSH_USBCONSOLE
+ ---help---
+ If NSH_CONSOLE is set to 'y', then 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:
+ 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_ARCHINIT
+ bool "Have architecture-specific initialization"
+ default n
+ ---help---
+ 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.
+
+config NSH_TELNET
+ bool "Use Telnet console"
+ default n
+ depends on NET && NET_TCP
+ ---help---
+ If 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.
+
+endif
+
+if NSH_TELNET
+config NSH_TELNETD_PORT
+ int "Telnet port number"
+ default 23
+ ---help---
+ The telnet daemon will listen on this TCP port number for connections.
+ Default: 23
+
+config NSH_TELNETD_DAEMONPRIO
+ int "Telnet daemon priority"
+ default 100
+ ---help---
+ Priority of the Telnet daemon. Default: 100
+
+config NSH_TELNETD_DAEMONSTACKSIZE
+ int "Telnet daemon stack size"
+ default 2048
+ ---help---
+ Stack size allocated for the Telnet daemon. Default: 2048
+
+config NSH_TELNETD_CLIENTPRIO
+ int "Telnet client priority"
+ default 100
+ ---help---
+ Priority of the Telnet client. Default: 100
+
+config NSH_TELNETD_CLIENTSTACKSIZE
+ int "Telnet client stack size"
+ default 2048
+ ---help---
+ Stack size allocated for the Telnet client. Default: 2048
+
+config NSH_IOBUFFER_SIZE
+ int "Telnet I/O buffer size"
+ default 512
+ ---help---
+ Determines the size of the I/O buffer to use for sending/
+ receiving TELNET commands/reponses. Default: 512
+endif
+
+config NSH_DHCPC
+ bool "Use DHCP to get IP address"
+ default n
+ depends on NSH_LIBRARY && NET && NET_UDP && NET_BROADCAST
+ ---help---
+ Obtain the IP address via DHCP.
+
+ 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).
+
+config NSH_IPADDR
+ hex "Target IP address"
+ default 0x10000002
+ depends on NSH_LIBRARY && NET && !NSH_DHCPC
+ ---help---
+ If NSH_DHCPC is NOT set, then the static IP address must be provided.
+ This is a 32-bit integer value in host order. So, as an example,
+ 0x10000002 would be 10.0.0.2.
+
+config NSH_DRIPADDR
+ hex "Router IP address"
+ default 0x10000001
+ depends on NSH_LIBRARY && NET && !NSH_DHCPC
+ ---help---
+ Default router IP address (aka, Gateway). This is a 32-bit integer
+ value in host order. So, as an example, 0x10000001 would be 10.0.0.1.
+
+config NSH_NETMASK
+ hex "Network mask"
+ default 0xffffff00
+ depends on NSH_LIBRARY && NET && !NSH_DHCPC
+ ---help---
+ Network mask. This is a 32-bit integer value in host order. So, as
+ an example, 0xffffff00 would be 255.255.255.0.
+
+config NSH_NOMAC
+ bool "Hardware has no MAC address"
+ default n
+ depends on NSH_LIBRARY && NET
+ ---help---
+ Set if your ethernet hardware has no built-in MAC address.
+ If set, a bogus MAC will be assigned.
diff --git a/apps/nshlib/Make.defs b/apps/nshlib/Make.defs
new file mode 100644
index 000000000..2bacb5b79
--- /dev/null
+++ b/apps/nshlib/Make.defs
@@ -0,0 +1,40 @@
+############################################################################
+# apps/nshlib/Make.defs
+# Adds selected applications to apps/ build
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_NSH_LIBRARY),y)
+CONFIGURED_APPS += nshlib
+endif
+
diff --git a/apps/nshlib/Makefile b/apps/nshlib/Makefile
new file mode 100644
index 000000000..f616374bf
--- /dev/null
+++ b/apps/nshlib/Makefile
@@ -0,0 +1,131 @@
+############################################################################
+# apps/nshlib/Makefile
+#
+# Copyright (C) 2011-2012 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
+
+# NSH Library
+
+ASRCS =
+CSRCS = nsh_init.c nsh_parse.c nsh_console.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
+
+ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y)
+CSRCS += nsh_mntcmds.c
+endif
+
+ifeq ($(CONFIG_NSH_CONSOLE),y)
+CSRCS += nsh_consolemain.c
+endif
+
+ifeq ($(CONFIG_NSH_TELNET),y)
+CSRCS += nsh_telnetd.c
+endif
+
+ifneq ($(CONFIG_NSH_DISABLESCRIPT),y)
+CSRCS += nsh_test.c
+endif
+
+ifeq ($(CONFIG_USBDEV),y)
+CSRCS += nsh_usbdev.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..0f6aee759
--- /dev/null
+++ b/apps/nshlib/README.txt
@@ -0,0 +1,1170 @@
+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 df
+
+ Show the state of each mounted volume.
+
+ Example:
+
+ nsh> mount
+ /etc type romfs
+ /tmp type vfat
+ nsh> df
+ Block Number
+ Size Blocks Used Available Mounted on
+ 64 6 6 0 /etc
+ 512 985 2 983 /tmp
+ nsh>
+
+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 [-v] [<cmd>]
+
+ Presents summary information about NSH commands to console. Options:
+
+ -v
+ Show verbose output will full command usage
+
+ <cmd>
+ Show full command usage only for this command
+
+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 pseudo filesystem and
+ must have been created by some call to register_blockdriver() (see
+ include/nuttx/fs/fs.h).
+
+o mkfifo <path>
+
+ Creates a FIFO character device anywhere in the pseudo file system,
+ creating whatever pseudo 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 performs one of two different operations. If no
+ paramters are provided on the command line after the mount command,
+ then the 'mount' command will enumerate all of the current
+ mountpoints on the console.
+
+ If the mount parameters are provied on the command after the 'mount'
+ command, then the 'mount' command will mount a file system in the
+ NuttX pseudo-file system. 'mount' performs a three way association,
+ 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 pseudo 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 pseudo file
+ system where the mounted volume will appear. This mount point
+ can only reside in the NuttX pseudo filesystem. By convention, this
+ mount point is a subdirectory under /mnt. The mount command will
+ create whatever pseudo 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 pseudo file
+ system, it may be access in the same way as other objects in the
+ file system.
+
+ Examples:
+ ^^^^^^^^^
+
+ 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>
+
+ nsh> mount
+ /etc type romfs
+ /tmp type vfat
+ /mnt/fs type vfat
+
+o mv <old-path> <new-path>
+
+ Rename the file object at <old-path> to <new-path>. Both paths must
+ reside in the same mounted filesystem.
+
+o nfsmount <server-address> <mount-point> <remote-path>
+
+ Mount the remote NFS server directory <remote-path> at <mount-point> on the target machine.
+ <server-address> is the IP address of the remote server.
+
+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
+ df !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_READABLE (see note 3)
+ 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)
+ mv !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE (see note 4)
+ nfsmount !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NET && CONFIG_NFS
+ 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_DF, 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_MV,
+ CONFIG_NSH_DISABLE_NFSMOUNT, 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
+
+Verbose help output can be suppressed by defining CONFIG_NSH_HELP_TERSE. In that
+case, the help command is still available but will be slightly smaller.
+
+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'.
+ This setting depends upon the strerror() having been enabled
+ with CONFIG_LIBC_STRERROR.
+
+ * CONFIG_NSH_LINELEN
+ The maximum length of one command line and of one output line.
+ Default: 80
+
+ * 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.
+
+ Normally, the serial console device is a UART and RS-232
+ interface. However, if CONFIG_USBDEV is defined, then a USB
+ serial device may, instead, be used if the one of
+ the following are defined:
+
+ CONFIG_PL2303 and CONFIG_PL2303_CONSOLE - Sets up the
+ Prolifics PL2303 emulation as a console device
+ at /dev/console.
+
+ CONFIG_CDCACM and CONFIG_CDCACM_CONSOLE - Sets up the
+ CDC/ACM serial device as a console device at
+ dev/console.
+
+ CONFIG_NSH_USBCONSOLE
+ If defined, then the an arbitrary USB device may be used
+ to as the NSH console. In this case, CONFIG_NSH_USBCONDEV
+ must be defined to indicate which USB device to use as
+ the console.
+
+ CONFIG_NSH_USBCONDEV
+ If CONFIG_NSH_USBCONSOLE is set to 'y', then CONFIG_NSH_USBCONDEV
+ must also be set to select the USB device used to support
+ the NSH console. This should be set to the quoted name of a
+ readable/write-able USB driver such as:
+ CONFIG_NSH_USBCONDEV="/dev/ttyACM0".
+
+ If there are more than one USB devices, then a USB device
+ minor number may also need to be provided:
+
+ CONFIG_NSH_UBSDEV_MINOR
+ The minor device number of the USB device. Default: 0
+
+ If USB tracing is enabled (CONFIG_USBDEV_TRACE), then NSH will
+ initialize USB tracing as requested by the following. Default:
+ Only USB errors are traced.
+
+ CONFIG_NSH_USBDEV_TRACEINIT
+ Show initialization events
+ CONFIG_NSH_USBDEV_TRACECLASS
+ Show class driver events
+ CONFIG_NSH_USBDEV_TRACETRANSFERS
+ Show data transfer events
+ CONFIG_NSH_USBDEV_TRACECONTROLLER
+ Show controller events
+ CONFIG_NSH_USBDEV_TRACEINTERRUPTS
+ Show interrupt-related events.
+
+ * 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.
+
+ If Telnet is selected for the NSH console, then we must configure
+ the resources used by the Telnet daemon and by the Telnet clients.
+
+ * CONFIG_NSH_TELNETD_PORT - The telnet daemon will listen on this
+ TCP port number for connections. Default: 23
+
+ * CONFIG_NSH_TELNETD_DAEMONPRIO - Priority of the Telnet daemon.
+ Default: SCHED_PRIORITY_DEFAULT
+
+ * CONFIG_NSH_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the
+ Telnet daemon. Default: 2048
+
+ * CONFIG_NSH_TELNETD_CLIENTPRIO- Priority of the Telnet client.
+ Default: SCHED_PRIORITY_DEFAULT
+
+ * CONFIG_NSH_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the
+ Telnet client. Default: 2048
+
+ 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.
+
+ Problem:
+ The function 'readline' is undefined.
+ Usual Cause:
+ The following is missing from your appconfig file:
+
+ CONFIGURED_APPS += system/readline
+
diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h
new file mode 100644
index 000000000..dac91ba05
--- /dev/null
+++ b/apps/nshlib/nsh.h
@@ -0,0 +1,611 @@
+/****************************************************************************
+ * apps/nshlib/nsh.h
+ *
+ * Copyright (C) 2007-2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_NSHLIB_NSH_H
+#define __APPS_NSHLIB_NSH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <nuttx/usb/usbdev_trace.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* The background commands require pthread support */
+
+#ifdef CONFIG_DISABLE_PTHREAD
+# 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
+
+/* If a USB device is selected for the NSH console then we need to handle some
+ * special start-up conditions.
+ */
+
+#undef HAVE_USB_CONSOLE
+#if defined(CONFIG_USBDEV)
+
+/* Check for a PL2303 serial console. Use console device "/dev/console". */
+
+# if defined(CONFIG_PL2303) && defined(CONFIG_PL2303_CONSOLE)
+# define HAVE_USB_CONSOLE 1
+
+/* Check for a CDC/ACM serial console. Use console device "/dev/console". */
+
+# elif defined(CONFIG_CDCACM) && defined(CONFIG_CDCACM_CONSOLE)
+# define HAVE_USB_CONSOLE 1
+
+/* Check for other USB console. USB console device must be provided in CONFIG_NSH_CONDEV */
+
+# elif defined(CONFIG_NSH_USBCONSOLE)
+# define HAVE_USB_CONSOLE 1
+# endif
+#endif
+
+/* Defaults for the USB console */
+
+#ifdef HAVE_USB_CONSOLE
+
+/* The default USB console device minor number is 0*/
+
+# ifndef CONFIG_NSH_UBSDEV_MINOR
+# define CONFIG_NSH_UBSDEV_MINOR 0
+# endif
+
+/* The default console device is always /dev/console */
+
+# ifndef CONFIG_NSH_USBCONDEV
+# define CONFIG_NSH_USBCONDEV "/dev/console"
+# endif
+
+/* USB trace settings */
+
+#ifdef CONFIG_NSH_USBDEV_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_NSH_USBDEV_TRACECLASS
+# define TRACE_CLASS_BITS (TRACE_CLASS_BIT|TRACE_CLASSAPI_BIT|TRACE_CLASSSTATE_BIT)
+#else
+# define TRACE_CLASS_BITS (0)
+#endif
+
+#ifdef CONFIG_NSH_USBDEV_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_NSH_USBDEV_TRACECONTROLLER
+# define TRACE_CONTROLLER_BITS (TRACE_EP_BIT|TRACE_DEV_BIT)
+#else
+# define TRACE_CONTROLLER_BITS (0)
+#endif
+
+#ifdef CONFIG_NSH_USBDEV_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)
+
+#endif
+
+/* If Telnet is selected for the NSH console, then we must configure
+ * the resources used by the Telnet daemon and by the Telnet clients.
+ *
+ * CONFIG_NSH_TELNETD_PORT - The telnet daemon will listen on this.
+ * port. Default: 23
+ * CONFIG_NSH_TELNETD_DAEMONPRIO - Priority of the Telnet daemon.
+ * Default: SCHED_PRIORITY_DEFAULT
+ * CONFIG_NSH_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the
+ * Telnet daemon. Default: 2048
+ * CONFIG_NSH_TELNETD_CLIENTPRIO- Priority of the Telnet client.
+ * Default: SCHED_PRIORITY_DEFAULT
+ * CONFIG_NSH_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the
+ * Telnet client. Default: 2048
+ */
+
+#ifndef CONFIG_NSH_TELNETD_PORT
+# define CONFIG_NSH_TELNETD_PORT 23
+#endif
+
+#ifndef CONFIG_NSH_TELNETD_DAEMONPRIO
+# define CONFIG_NSH_TELNETD_DAEMONPRIO SCHED_PRIORITY_DEFAULT
+#endif
+
+#ifndef CONFIG_NSH_TELNETD_DAEMONSTACKSIZE
+# define CONFIG_NSH_TELNETD_DAEMONSTACKSIZE 2048
+#endif
+
+#ifndef CONFIG_NSH_TELNETD_CLIENTPRIO
+# define CONFIG_NSH_TELNETD_CLIENTPRIO SCHED_PRIORITY_DEFAULT
+#endif
+
+#ifndef CONFIG_NSH_TELNETD_CLIENTSTACKSIZE
+# define CONFIG_NSH_TELNETD_CLIENTSTACKSIZE 2048
+#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. Note that the strerror
+ * interface must also have been enabled with CONFIG_LIBC_STRERROR.
+ */
+
+#ifndef CONFIG_LIBC_STRERROR
+# undef CONFIG_NSH_STRERROR
+#endif
+
+#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
+
+/* 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
+
+/* 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
+
+/* 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
+
+/****************************************************************************
+ * 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; /* Defined in nsh_console.h */
+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
+int nsh_romfsetc(void);
+#else
+# define nsh_romfsetc() (-ENOSYS)
+#endif
+
+#ifdef CONFIG_NET
+int nsh_netinit(void);
+#else
+# define nsh_netinit() (-ENOSYS)
+#endif
+
+#ifdef HAVE_USB_CONSOLE
+int nsh_usbconsole(void);
+#else
+# define nsh_usbconsole() (-ENOSYS)
+#endif
+
+#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);
+#endif
+
+/* Architecture-specific initialization */
+
+#ifdef CONFIG_NSH_ARCHINIT
+int nsh_archinitialize(void);
+#else
+# define nsh_archinitialize() (-ENOSYS)
+#endif
+
+/* Message handler */
+
+int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline);
+
+/* Application interface */
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+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)
+FAR const char *nsh_getcwd(void);
+char *nsh_getfullpath(FAR struct nsh_vtbl_s *vtbl, const char *relpath);
+void nsh_freefullpath(char *relpath);
+#endif
+
+/* Debug */
+
+void nsh_dumpbuffer(FAR struct nsh_vtbl_s *vtbl, const char *msg,
+ const uint8_t *buffer, ssize_t nbytes);
+
+/* USB debug support */
+
+#if defined(CONFIG_USBDEV_TRACE) && defined(HAVE_USB_CONSOLE)
+void nsh_usbtrace(void);
+#else
+# define nsh_usbtrace()
+#endif
+
+/* Shell command handlers */
+
+#ifndef CONFIG_NSH_DISABLE_ECHO
+ int cmd_echo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_NSH_DISABLE_EXEC
+ int cmd_exec(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_NSH_DISABLE_MB
+ int cmd_mb(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_NSH_DISABLE_MH
+ int cmd_mh(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_NSH_DISABLE_MW
+ int cmd_mw(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_NSH_DISABLE_FREE
+ int cmd_free(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_NSH_DISABLE_PS
+ int cmd_ps(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+#ifndef CONFIG_NSH_DISABLE_XD
+ int cmd_xd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+#endif
+
+#if !defined(CONFIG_NSH_DISABLESCRIPT) && !defined(CONFIG_NSH_DISABLE_TEST)
+ int cmd_test(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+ 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)
+ 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
+ int cmd_cat(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_CP
+ int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_DD
+ int cmd_dd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_LS
+ int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# if defined(CONFIG_SYSLOG) && defined(CONFIG_RAMLOG_SYSLOG) && !defined(CONFIG_NSH_DISABLE_DMESG)
+ int cmd_dmesg(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
+ 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
+ int cmd_losetup(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_MKFIFO
+ int cmd_mkfifo(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifdef CONFIG_FS_READABLE
+# ifndef CONFIG_NSH_DISABLE_DF
+ int cmd_df(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_MOUNT
+ int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_UMOUNT
+ int cmd_umount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifdef CONFIG_FS_WRITABLE
+# ifndef CONFIG_NSH_DISABLE_MKDIR
+ int cmd_mkdir(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_MKRD
+ int cmd_mkrd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_MV
+ int cmd_mv(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_RM
+ int cmd_rm(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_RMDIR
+ 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
+ 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
+ int cmd_cd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_PWD
+ 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
+ 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
+ int cmd_get(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_PUT
+ 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
+ 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
+ int cmd_ping(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+#endif
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && \
+ defined(CONFIG_FS_READABLE) && defined(CONFIG_NFS)
+# ifndef CONFIG_NSH_DISABLE_NFSMOUNT
+ int cmd_nfsmount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+#endif
+#endif
+
+#ifndef CONFIG_DISABLE_ENVIRON
+# ifndef CONFIG_NSH_DISABLE_SET
+ int cmd_set(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_UNSET
+ 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
+ int cmd_kill(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_SLEEP
+ int cmd_sleep(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_USLEEP
+ 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..e335c2e2c
--- /dev/null
+++ b/apps/nshlib/nsh_apps.c
@@ -0,0 +1,187 @@
+/****************************************************************************
+ * apps/nshlib/nsh_apps.c
+ *
+ * Copyright (C) 2011-2012 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"
+#include "nsh_console.h"
+
+#ifdef CONFIG_NSH_BUILTIN_APPS
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_execapp
+ *
+ * Description:
+ * Attempt to execute the application task whose name is 'cmd'
+ *
+ * Returned Value:
+ * <0 If exec_namedapp() fails, then the negated errno value
+ * is returned.
+ * -1 (ERROR) if the application task corresponding to 'cmd' could not
+ * be started (possibly because it doesn not exist).
+ * 0 (OK) if the application task corresponding to 'cmd' was
+ * and successfully started. If CONFIG_SCHED_WAITPID is
+ * defined, this return value also indicates that the
+ * application returned successful status (EXIT_SUCCESS)
+ * 1 If CONFIG_SCHED_WAITPID is defined, then this return value
+ * indicates that the application task was spawned successfully
+ * but returned failure exit status.
+ *
+ ****************************************************************************/
+
+int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
+ FAR char **argv)
+{
+ int ret = OK;
+
+ /* Lock the scheduler to prevent the application from running until the
+ * waitpid() has been called.
+ */
+
+ sched_lock();
+
+ /* Try to find and execute the command within the list of builtin
+ * applications.
+ */
+
+ ret = exec_namedapp(cmd, (FAR const char **)argv);
+ if (ret >= 0)
+ {
+ /* The application was successfully started (but still blocked because the
+ * scheduler is locked). If the application was not backgrounded, then we
+ * need to wait here for the application to exit.
+ */
+
+#ifdef CONFIG_SCHED_WAITPID
+ if (vtbl->np.np_bg == false)
+ {
+ int rc = 0;
+
+ /* Wait for the application to exit. Since we have locked the
+ * scheduler above, we know that the application has not yet
+ * started and there is no possibility that it has already exited.
+ * The scheduler will be unlocked while waitpid is waiting and the
+ * application will be able to run.
+ */
+
+ ret = waitpid(ret, &rc, 0);
+ if (ret >= 0)
+ {
+ /* We can't return the exact status (nsh has nowhere to put it)
+ * so just pass back zero/nonzero in a fashion that doesn't look
+ * like an error.
+ */
+
+ ret = (rc == 0) ? OK : 1;
+
+ /* TODO: Set the environment variable '?' to a string corresponding
+ * to WEXITSTATUS(rc) so that $? will expand to the exit status of
+ * the most recently executed task.
+ */
+ }
+ }
+ else
+#endif
+ {
+ struct sched_param param;
+ sched_getparam(0, &param);
+ nsh_output(vtbl, "%s [%d:%d]\n", cmd, ret, param.sched_priority);
+
+ /* Backgrounded commands always 'succeed' as long as we can start
+ * them.
+ */
+
+ ret = OK;
+ }
+ }
+
+ sched_unlock();
+
+ /* If exec_namedapp() or waitpid() failed, then return the negated errno
+ * value.
+ */
+
+ if (ret < 0)
+ {
+ return -errno;
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_NSH_BUILTIN_APPS */
diff --git a/apps/nshlib/nsh_console.c b/apps/nshlib/nsh_console.c
new file mode 100644
index 000000000..b066e71f5
--- /dev/null
+++ b/apps/nshlib/nsh_console.c
@@ -0,0 +1,432 @@
+/****************************************************************************
+ * apps/nshlib/nsh_serial.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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 <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"
+#include "nsh_console.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct serialsave_s
+{
+ int cn_outfd; /* Re-directed output file descriptor */
+ FILE *cn_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);
+#endif
+static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl);
+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, int exitstatus);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_openifnotopen
+ ****************************************************************************/
+
+static int nsh_openifnotopen(struct console_stdio_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->cn_outstream)
+ {
+ pstate->cn_outstream = fdopen(pstate->cn_outfd, "w");
+ if (!pstate->cn_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 console_stdio_s *pstate)
+{
+ if (pstate->cn_outstream == OUTSTREAM(pstate))
+ {
+ fflush(OUTSTREAM(pstate));
+ pstate->cn_outfd = OUTFD(pstate);
+ }
+ else
+ {
+ if (pstate->cn_outstream)
+ {
+ fflush(pstate->cn_outstream);
+ fclose(pstate->cn_outstream);
+ }
+ else if (pstate->cn_outfd >= 0 && pstate->cn_outfd != OUTFD(pstate))
+ {
+ close(pstate->cn_outfd);
+ }
+
+ pstate->cn_outfd = -1;
+ pstate->cn_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 console_stdio_s *pstate = (FAR struct console_stdio_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->cn_outstream);
+ if (ret < 0)
+ {
+ dbg("[%d] Failed to send buffer: %d\n", pstate->cn_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 console_stdio_s *pstate = (FAR struct console_stdio_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->cn_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 console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
+ return pstate->cn_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 console_stdio_s *pclone = nsh_newconsole();
+ return &pclone->cn_vtbl;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_consolerelease
+ *
+ * Description:
+ * Release the cloned instance
+ *
+ ****************************************************************************/
+
+static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl)
+{
+ FAR struct console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
+
+ /* Close the output stream */
+
+ nsh_closeifnotclosed(pstate);
+
+ /* Close the console stream */
+
+#ifdef CONFIG_NSH_CONDEV
+ (void)fclose(pstate->cn_constream);
+#endif
+
+ /* Then release the vtable container */
+
+ free(pstate);
+}
+
+/****************************************************************************
+ * 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 console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
+ FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save;
+
+ /* Case 1: Redirected foreground commands */
+
+ if (ssave)
+ {
+ /* pstate->cn_outstream and cn_outfd refer refer to the
+ * currently opened output stream. If the output stream is open, flush
+ * any pending output.
+ */
+
+ if (pstate->cn_outstream)
+ {
+ fflush(pstate->cn_outstream);
+ }
+
+ /* Save the current fd and stream values. These will be restored
+ * when nsh_consoleundirect() is called.
+ */
+
+ ssave->cn_outfd = pstate->cn_outfd;
+ ssave->cn_outstream = pstate->cn_outstream;
+ }
+ else
+ {
+ /* nsh_consoleclone() set pstate->cn_outfd and cn_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->cn_outfd = fd;
+ pstate->cn_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 console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
+ FAR struct serialsave_s *ssave = (FAR struct serialsave_s *)save;
+
+ nsh_closeifnotclosed(pstate);
+ pstate->cn_outfd = ssave->cn_outfd;
+ pstate->cn_outstream = ssave->cn_outstream;
+}
+
+/****************************************************************************
+ * Name: nsh_consoleexit
+ *
+ * Description:
+ * Exit the shell task
+ *
+ ****************************************************************************/
+
+static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl, int exitstatus)
+{
+ /* Destroy ourself then exit with the provided status */
+
+ nsh_consolerelease(vtbl);
+ exit(exitstatus);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_newconsole
+ ****************************************************************************/
+
+FAR struct console_stdio_s *nsh_newconsole(void)
+{
+ struct console_stdio_s *pstate = (struct console_stdio_s *)zalloc(sizeof(struct console_stdio_s));
+ if (pstate)
+ {
+ /* Initialize the call table */
+
+#ifndef CONFIG_NSH_DISABLEBG
+ pstate->cn_vtbl.clone = nsh_consoleclone;
+ pstate->cn_vtbl.release = nsh_consolerelease;
+#endif
+ pstate->cn_vtbl.write = nsh_consolewrite;
+ pstate->cn_vtbl.output = nsh_consoleoutput;
+ pstate->cn_vtbl.linebuffer = nsh_consolelinebuffer;
+ pstate->cn_vtbl.redirect = nsh_consoleredirect;
+ pstate->cn_vtbl.undirect = nsh_consoleundirect;
+ pstate->cn_vtbl.exit = nsh_consoleexit;
+
+ /* (Re-) open the console input device */
+
+#ifdef CONFIG_NSH_CONDEV
+ pstate->cn_confd = open(CONFIG_NSH_CONDEV, O_RDWR);
+ if (pstate->cn_confd < 0)
+ {
+ free(pstate);
+ return NULL;
+ }
+
+ /* Create a standard C stream on the console device */
+
+ pstate->cn_constream = fdopen(pstate->cn_confd, "r+");
+ if (!pstate->cn_constream)
+ {
+ close(pstate->cn_confd);
+ free(pstate);
+ return NULL;
+ }
+#endif
+
+ /* Initialize the output stream */
+
+ pstate->cn_outfd = OUTFD(pstate);
+ pstate->cn_outstream = OUTSTREAM(pstate);
+ }
+ return pstate;
+}
diff --git a/apps/nshlib/nsh_console.h b/apps/nshlib/nsh_console.h
new file mode 100644
index 000000000..53e8c7897
--- /dev/null
+++ b/apps/nshlib/nsh_console.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+ * apps/nshlib/nsh_console.h
+ *
+ * Copyright (C) 2007-2012 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_NSHLIB_NSH_CONSOLE_H
+#define __APPS_NSHLIB_NSH_CONSOLE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* 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,s) (v)->exit(v,s)
+
+#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))
+
+/* Are we using the NuttX console for I/O? Or some other character device? */
+
+#ifdef CONFIG_NSH_CONDEV
+# define INFD(p) ((p)->cn_confd)
+# define INSTREAM(p) ((p)->cn_constream)
+# define OUTFD(p) ((p)->cn_confd)
+# define OUTSTREAM(p) ((p)->cn_constream)
+#else
+# define INFD(p) 0
+# define INSTREAM(p) stdin
+# define OUTFD(p) 1
+# define OUTSTREAM(p) stdout
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+/* This describes a generic console front-end */
+
+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, int exitstatus);
+
+ /* Parser state data */
+
+ struct nsh_parser_s np;
+};
+
+/* This structure describes a console front-end that is based on stdin and
+ * stdout (which is all of the supported console types at the time being).
+ */
+
+struct console_stdio_s
+{
+ /* NSH front-end call table */
+
+ struct nsh_vtbl_s cn_vtbl;
+
+ /* NSH input/output streams */
+
+#ifdef CONFIG_NSH_CONDEV
+ int cn_confd; /* Console I/O file descriptor */
+#endif
+ int cn_outfd; /* Output file descriptor (possibly redirected) */
+#ifdef CONFIG_NSH_CONDEV
+ FILE *cn_constream; /* Console I/O stream (possibly redirected) */
+#endif
+ FILE *cn_outstream; /* Output stream */
+
+ /* Line input buffer */
+
+ char cn_line[CONFIG_NSH_LINELEN];
+};
+
+
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* Defined in nsh_console.c *************************************************/
+
+FAR struct console_stdio_s *nsh_newconsole(void);
+
+#endif /* __APPS_NSHLIB_NSH_CONSOLE_H */
diff --git a/apps/nshlib/nsh_consolemain.c b/apps/nshlib/nsh_consolemain.c
new file mode 100644
index 000000000..6b51be470
--- /dev/null
+++ b/apps/nshlib/nsh_consolemain.c
@@ -0,0 +1,170 @@
+/****************************************************************************
+ * apps/nshlib/nsh_consolemain.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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 <stdio.h>
+#include <assert.h>
+
+#include <apps/readline.h>
+
+#include "nsh.h"
+#include "nsh_console.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_consolemain
+ *
+ * Description:
+ * This interfaces maybe to called or started with task_start to start a
+ * single an NSH instance that operates on stdin and stdout (/dev/console).
+ * This function does not return.
+ *
+ * Input Parameters:
+ * Standard task start-up arguements. These are not used. argc may be
+ * zero and argv may be NULL.
+ *
+ * Returned Values:
+ * This function does not normally return. exit() is usually called to
+ * terminate the NSH session. This function will return in the event of
+ * an error. In that case, a nonzero value is returned (1).
+ *
+ ****************************************************************************/
+
+int nsh_consolemain(int argc, char *argv[])
+{
+ FAR struct console_stdio_s *pstate = nsh_newconsole();
+ int ret;
+
+ DEBUGASSERT(pstate);
+
+ /* If we are using a USB serial console, then we will have to wait for the
+ * USB to be connected to the host.
+ */
+
+#ifdef HAVE_USB_CONSOLE
+ ret = nsh_usbconsole();
+ DEBUGASSERT(ret == OK);
+#endif
+
+ /* Present a greeting */
+
+ fputs(g_nshgreeting, pstate->cn_outstream);
+ fflush(pstate->cn_outstream);
+
+ /* Execute the startup script */
+
+#ifdef CONFIG_NSH_ROMFSETC
+ (void)nsh_script(&pstate->cn_vtbl, "init", NSH_INITPATH);
+#endif
+
+ /* Then enter the command line parsing loop */
+
+ for (;;)
+ {
+ /* For the case of debugging the USB console... dump collected USB trace data */
+
+ nsh_usbtrace();
+
+ /* Display the prompt string */
+
+ fputs(g_nshprompt, pstate->cn_outstream);
+ fflush(pstate->cn_outstream);
+
+ /* Get the next line of input */
+
+ ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN,
+ INSTREAM(pstate), OUTSTREAM(pstate));
+ if (ret > 0)
+ {
+ /* Parse process the command */
+
+ (void)nsh_parse(&pstate->cn_vtbl, pstate->cn_line);
+ fflush(pstate->cn_outstream);
+ }
+
+ /* Readline normally returns the number of characters read,
+ * but will return 0 on end of file or a negative value
+ * if an error occurs. Either will cause the session to
+ * terminate.
+ */
+
+ else
+ {
+ fprintf(pstate->cn_outstream, g_fmtcmdfailed, "nsh_consolemain",
+ "readline", NSH_ERRNO_OF(-ret));
+ nsh_exit(&pstate->cn_vtbl, 1);
+ }
+ }
+
+ /* Clean up */
+
+ nsh_exit(&pstate->cn_vtbl, 0);
+
+ /* We do not get here, but this is necessary to keep some compilers happy */
+
+ return OK;
+}
diff --git a/apps/nshlib/nsh_dbgcmds.c b/apps/nshlib/nsh_dbgcmds.c
new file mode 100644
index 000000000..384b377f3
--- /dev/null
+++ b/apps/nshlib/nsh_dbgcmds.c
@@ -0,0 +1,355 @@
+/****************************************************************************
+ * apps/nshlib/dbg_dbgcmds.c
+ *
+ * Copyright (C) 2008-2009, 2011-2012 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 <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "nsh.h"
+#include "nsh_console.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..40a3710b1
--- /dev/null
+++ b/apps/nshlib/nsh_ddcmd.c
@@ -0,0 +1,643 @@
+/****************************************************************************
+ * apps/nshlib/nsh_ddcmd.c
+ *
+ * Copyright (C) 2008-2009, 2012 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 <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/fs.h>
+
+#include "nsh.h"
+#include "nsh_console.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..07b775517
--- /dev/null
+++ b/apps/nshlib/nsh_envcmds.c
@@ -0,0 +1,338 @@
+/****************************************************************************
+ * apps/nshlib/nsh_envcmds.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libgen.h>
+#include <errno.h>
+
+#include "nsh.h"
+#include "nsh_console.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..1a9f2eb57
--- /dev/null
+++ b/apps/nshlib/nsh_fscmds.c
@@ -0,0 +1,1299 @@
+/****************************************************************************
+ * apps/nshlib/nsh_fscmds.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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 <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/fs/mkfatfs.h>
+# endif
+# ifdef CONFIG_NFS
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <nuttx/fs/nfs.h>
+# endif
+# ifdef CONFIG_RAMLOG_SYSLOG
+# include <nuttx/ramlog.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"
+#include "nsh_console.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+#define LSFLAGS_SIZE 1
+#define LSFLAGS_LONG 2
+#define LSFLAGS_RECURSIVE 4
+
+/****************************************************************************
+ * 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
+
+/****************************************************************************
+ * Name: cat_common
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0
+#ifndef CONFIG_NSH_DISABLE_CAT
+static int cat_common(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
+ FAR const char *filename)
+{
+ char buffer[IOBUFFERSIZE];
+ int fd;
+ int ret = OK;
+
+ /* Open the file for reading */
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "open", NSH_ERRNO);
+ return ERROR;
+ }
+
+ /* And just dump it byte for byte into stdout */
+
+ for (;;)
+ {
+ int nbytesread = read(fd, buffer, IOBUFFERSIZE);
+
+ /* Check for read errors */
+
+ if (nbytesread < 0)
+ {
+ int errval = errno;
+
+ /* EINTR is not an error (but will stop stop the cat) */
+
+#ifndef CONFIG_DISABLE_SIGNALS
+ if (errval == EINTR)
+ {
+ nsh_output(vtbl, g_fmtsignalrecvd, cmd);
+ }
+ else
+#endif
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "read", NSH_ERRNO_OF(errval));
+ }
+
+ 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)
+ {
+ int errval = errno;
+
+ /* EINTR is not an error (but will stop stop the cat) */
+
+ #ifndef CONFIG_DISABLE_SIGNALS
+ if (errval == EINTR)
+ {
+ nsh_output(vtbl, g_fmtsignalrecvd, cmd);
+ }
+ else
+#endif
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, cmd, "write", NSH_ERRNO);
+ }
+
+ ret = ERROR;
+ break;
+ }
+ else
+ {
+ nbyteswritten += n;
+ }
+ }
+ }
+
+ /* Otherwise, it is the end of file */
+
+ else
+ {
+ break;
+ }
+ }
+
+ (void)close(fd);
+ return ret;
+}
+#endif
+#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 *fullpath;
+ 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)
+ {
+ ret = ERROR;
+ }
+ else
+ {
+ /* Dump the file to the console */
+
+ ret = cat_common(vtbl, argv[0], fullpath);
+
+ /* Free the allocated full path */
+
+ nsh_freefullpath(fullpath);
+ }
+ }
+
+ return ret;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: cmd_dmesg
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_SYSLOG) && \
+ defined(CONFIG_RAMLOG_SYSLOG) && !defined(CONFIG_NSH_DISABLE_DMESG)
+int cmd_dmesg(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ return cat_common(vtbl, argv[0], CONFIG_SYSLOG_DEVPATH);
+}
+#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 mkrd 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_mv
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE)
+#ifndef CONFIG_NSH_DISABLE_MV
+int cmd_mv(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ char *oldpath;
+ char *newpath;
+ int ret;
+
+ /* Get the full path to the old and new file paths */
+
+ oldpath = nsh_getfullpath(vtbl, argv[1]);
+ if (!oldpath)
+ {
+ return ERROR;
+ }
+
+ newpath = nsh_getfullpath(vtbl, argv[2]);
+ if (!newpath)
+ {
+ nsh_freefullpath(newpath);
+ return ERROR;
+ }
+
+ /* Perform the mount */
+
+ ret = rename(oldpath, newpath);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "rename", NSH_ERRNO);
+ }
+
+ /* Free the file paths */
+
+ nsh_freefullpath(oldpath);
+ nsh_freefullpath(newpath);
+ 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
diff --git a/apps/nshlib/nsh_init.c b/apps/nshlib/nsh_init.c
new file mode 100644
index 000000000..7c7e78ea1
--- /dev/null
+++ b/apps/nshlib/nsh_init.c
@@ -0,0 +1,102 @@
+/****************************************************************************
+ * apps/nshlib/nsh_init.c
+ *
+ * Copyright (C) 2007-2012 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 "nsh.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_initialize
+ *
+ * Description:
+ * This nterfaces is used to initialize the NuttShell (NSH).
+ * nsh_initialize() should be called one during application start-up prior
+ * to executing either nsh_consolemain() or nsh_telnetstart().
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+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();
+}
+
diff --git a/apps/nshlib/nsh_mmcmds.c b/apps/nshlib/nsh_mmcmds.c
new file mode 100644
index 000000000..545ae60ad
--- /dev/null
+++ b/apps/nshlib/nsh_mmcmds.c
@@ -0,0 +1,96 @@
+/****************************************************************************
+ * apps/nshlib/nsh_mmcmds.c
+ *
+ * Copyright (C) 2011-2012 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 <stdlib.h>
+
+#include "nsh.h"
+#include "nsh_console.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 /* !CONFIG_NSH_DISABLE_FREE */
diff --git a/apps/nshlib/nsh_mntcmds.c b/apps/nshlib/nsh_mntcmds.c
new file mode 100644
index 000000000..690d027ca
--- /dev/null
+++ b/apps/nshlib/nsh_mntcmds.c
@@ -0,0 +1,434 @@
+/****************************************************************************
+ * apps/nshlib/nsh_mntcmds.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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 <sys/mount.h>
+#include <sys/statfs.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <debug.h>
+
+#include "nsh.h"
+#include "nsh_console.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: df_handler
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \
+ defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_MOUNT)
+static int df_handler(FAR const char *mountpoint,
+ FAR struct statfs *statbuf, FAR void *arg)
+{
+ FAR struct nsh_vtbl_s *vtbl = (FAR struct nsh_vtbl_s *)arg;
+
+ DEBUGASSERT(mountpoint && statbuf && vtbl);
+
+ nsh_output(vtbl, "%6ld %8ld %8ld %8ld %s\n",
+ statbuf->f_bsize, statbuf->f_blocks,
+ statbuf->f_blocks - statbuf->f_bavail, statbuf->f_bavail,
+ mountpoint);
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: mount_handler
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \
+ defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_MOUNT)
+static int mount_handler(FAR const char *mountpoint,
+ FAR struct statfs *statbuf, FAR void *arg)
+{
+ FAR struct nsh_vtbl_s *vtbl = (FAR struct nsh_vtbl_s *)arg;
+ FAR const char *fstype;
+
+ DEBUGASSERT(mountpoint && statbuf && vtbl);
+
+ /* Get the file system type */
+
+ switch (statbuf->f_type)
+ {
+#ifdef CONFIG_FS_FAT
+ case MSDOS_SUPER_MAGIC:
+ fstype = "vfat";
+ break;
+#endif
+
+#ifdef CONFIG_FS_ROMFS
+ case ROMFS_MAGIC:
+ fstype = "romfs";
+ break;
+#endif
+
+#ifdef CONFIG_APPS_BINDIR
+ case BINFS_MAGIC:
+ fstype = "bindir";
+ break;
+#endif
+
+#ifdef CONFIG_FS_NXFFS
+ case NXFFS_MAGIC:
+ fstype = "nxffs";
+ break;
+#endif
+
+#ifdef CONFIG_NFS
+ case NFS_SUPER_MAGIC:
+ fstype = "nfs";
+ break;
+#endif
+
+ default:
+ fstype = "Unrecognized";
+ break;
+ }
+
+ nsh_output(vtbl, " %s type %s\n", mountpoint, fstype);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: mount_show
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \
+ defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_MOUNT)
+static inline int mount_show(FAR struct nsh_vtbl_s *vtbl, FAR const char *progname)
+{
+ return foreach_mountpoint(mount_handler, (FAR void *)vtbl);
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cmd_df
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \
+ defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_DF)
+int cmd_df(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ nsh_output(vtbl, " Block Number\n");
+ nsh_output(vtbl, " Size Blocks Used Available Mounted on\n");
+
+ return foreach_mountpoint(df_handler, (FAR void *)vtbl);
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_mount
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \
+ defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_MOUNT)
+int cmd_mount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ FAR char *source;
+ FAR char *target;
+ FAR char *filesystem = NULL;
+ bool badarg = false;
+ int option;
+ int ret;
+
+ /* The mount command behaves differently if no parameters are provided */
+
+ if (argc < 2)
+ {
+ return mount_show(vtbl, argv[0]);
+ }
+
+ /* Get the mount options. NOTE: getopt() is not thread safe nor re-entrant.
+ * To keep its state proper for the next usage, it is necessary to parse to
+ * the end of the line even if an error occurs. If an error occurs, this
+ * logic just sets 'badarg' and continues.
+ */
+
+ 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: the source and target
+ * paths.
+ */
+
+ 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;
+ }
+
+ /* While the above parsing for the -t argument looks nice, the -t argument
+ * not really optional.
+ */
+
+ if (!filesystem)
+ {
+ nsh_output(vtbl, g_fmtargrequired, argv[0]);
+ return ERROR;
+ }
+
+ /* The source and target paths 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 (!target)
+ {
+ 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
+
+/****************************************************************************
+ * Name: cmd_nfsmount
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \
+ defined(CONFIG_NET) && defined(CONFIG_NFS) && !defined(CONFIG_NSH_DISABLE_NFSMOUNT)
+int cmd_nfsmount(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ struct nfs_args data;
+ FAR char *address;
+ FAR char *lpath;
+ FAR char *rpath;
+ bool badarg = false;
+#ifdef CONFIG_NET_IPv6
+ FAR struct sockaddr_in6 *sin;
+ struct in6_addr inaddr;
+#else
+ FAR struct sockaddr_in *sin;
+ struct in_addr inaddr;
+#endif
+ int ret;
+
+ /* If a bad argument was encountered, then return without processing the
+ * command.
+ */
+
+ if (badarg)
+ {
+ return ERROR;
+ }
+
+ /* The fist argument on the command line should be the NFS server IP address
+ * in standard IPv4 (or IPv6) dot format.
+ */
+
+ address = argv[1];
+ if (!address)
+ {
+ return ERROR;
+ }
+
+ /* The local mount point path (lpath) might be relative to the current working
+ * directory.
+ */
+
+ lpath = nsh_getfullpath(vtbl, argv[2]);
+ if (!lpath)
+ {
+ return ERROR;
+ }
+
+ /* Get the remote mount point path */
+
+ rpath = argv[3];
+
+ /* Convert the IP address string into its binary form */
+
+#ifdef CONFIG_NET_IPv6
+ ret = inet_pton(AF_INET6, address, &inaddr);
+#else
+ ret = inet_pton(AF_INET, address, &inaddr);
+#endif
+ if (ret != 1)
+ {
+ nsh_freefullpath(lpath);
+ return ERROR;
+ }
+
+ /* Place all of the NFS arguements into the nfs_args structure */
+
+ memset(&data, 0, sizeof(data));
+
+#ifdef CONFIG_NET_IPv6
+ sin = (FAR struct sockaddr_in6 *)&data.addr;
+ sin->sin_family = AF_INET6;
+ sin->sin_port = htons(NFS_PMAPPORT);
+ memcpy(&sin->sin6_addr, &inaddr, sizeof(struct in6_addr));
+ data.addrlen = sizeof(struct sockaddr_in6);
+#else
+ sin = (FAR struct sockaddr_in *)&data.addr;
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(NFS_PMAPPORT);
+ sin->sin_addr = inaddr;
+ data.addrlen = sizeof(struct sockaddr_in);
+#endif
+
+ data.sotype = SOCK_DGRAM;
+ data.path = rpath;
+ data.flags = 0; /* 0=Use all defaults */
+
+ /* Perform the mount */
+
+ ret = mount(NULL, lpath, "nfs", 0, (FAR void *)&data);
+ if (ret < 0)
+ {
+ nsh_output(vtbl, g_fmtcmdfailed, argv[0], "mount", NSH_ERRNO);
+ }
+
+ /* We no longer need the allocated mount point path */
+
+ nsh_freefullpath(lpath);
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_umount
+ ****************************************************************************/
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \
+ defined(CONFIG_FS_READABLE) && !defined(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
diff --git a/apps/nshlib/nsh_netcmds.c b/apps/nshlib/nsh_netcmds.c
new file mode 100644
index 000000000..cfea5a08a
--- /dev/null
+++ b/apps/nshlib/nsh_netcmds.c
@@ -0,0 +1,864 @@
+/****************************************************************************
+ * apps/nshlib/nsh_netcmds.c
+ *
+ * Copyright (C) 2007-2012 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>
+#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/net.h>
+#include <nuttx/clock.h>
+#include <net/ethernet.h>
+#include <nuttx/net/uip/uip.h>
+#include <nuttx/net/uip/uip-arch.h>
+#include <netinet/ether.h>
+
+#ifdef CONFIG_NET_STATISTICS
+# include <nuttx/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"
+#include "nsh_console.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..bc845c4ed
--- /dev/null
+++ b/apps/nshlib/nsh_netinit.c
@@ -0,0 +1,171 @@
+/****************************************************************************
+ * apps/nshlib/nsh_netinit.c
+ *
+ * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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] = 0xde;
+ mac[3] = 0xad;
+ mac[4] = 0xbe;
+ mac[5] = 0xef;
+ 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..ba597a062
--- /dev/null
+++ b/apps/nshlib/nsh_parse.c
@@ -0,0 +1,1550 @@
+/****************************************************************************
+ * apps/nshlib/nsh_parse.c
+ *
+ * Copyright (C) 2007-2012 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/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"
+#include "nsh_console.h"
+
+/****************************************************************************
+ * Pre-processor 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
+
+/* Help command summary layout */
+
+#define MAX_CMDLEN 12
+#define CMDS_PER_LINE 6
+
+#define NUM_CMDS ((sizeof(g_cmdmap)/sizeof(struct cmdmap_s)) - 1)
+#define NUM_CMD_ROWS ((NUM_CMDS + (CMDS_PER_LINE-1)) / CMDS_PER_LINE)
+
+/****************************************************************************
+ * 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 && !defined(CONFIG_NSH_DISABLE_DD)
+ { "dd", cmd_dd, 3, 6, "if=<infile> of=<outfile> [bs=<sectsize>] [count=<sectors>] [skip=<sectors>]" },
+# endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && \
+ defined(CONFIG_FS_READABLE) && !defined(CONFIG_NSH_DISABLE_DF)
+ { "df", cmd_df, 1, 1, NULL },
+#endif
+
+#if CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_SYSLOG) && \
+ defined(CONFIG_RAMLOG_SYSLOG) && !defined(CONFIG_NSH_DISABLE_DMESG)
+ { "dmesg", cmd_dmesg, 1, 1, NULL },
+#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
+# ifdef CONFIG_NSH_HELP_TERSE
+ { "help", cmd_help, 1, 2, "[<cmd>]" },
+#else
+ { "help", cmd_help, 1, 3, "[-v] [<cmd>]" },
+# endif
+#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, 1, 5, "[-t <fstype> <block-device> <mount-point>]" },
+# endif
+#endif
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && defined(CONFIG_FS_WRITABLE)
+# ifndef CONFIG_NSH_DISABLE_MV
+ { "mv", cmd_mv, 3, 3, "<old-path> <new-path>" },
+# endif
+#endif
+
+#ifndef CONFIG_NSH_DISABLE_MW
+ { "mw", cmd_mw, 2, 3, "<hex-address>[=<hex-value>][ <hex-byte-count>]" },
+#endif
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0 && \
+ defined(CONFIG_NET) && defined(CONFIG_NFS)
+# ifndef CONFIG_NSH_DISABLE_NFSMOUNT
+ { "nfsmount", cmd_nfsmount, 4, 4, "<server-address> <mount-point> <remote-path>" },
+# endif
+#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_WGET
+ { "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: help_cmdlist
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_HELP
+static inline void help_cmdlist(FAR struct nsh_vtbl_s *vtbl)
+{
+ int i;
+ int j;
+ int k;
+
+ /* Print the command name in NUM_CMD_ROWS rows with CMDS_PER_LINE commands
+ * on each line.
+ */
+
+ for (i = 0; i < NUM_CMD_ROWS; i++)
+ {
+ nsh_output(vtbl, " ");
+ for (j = 0, k = i; j < CMDS_PER_LINE && k < NUM_CMDS; j++, k += NUM_CMD_ROWS)
+ {
+ nsh_output(vtbl, "%-12s", g_cmdmap[k].cmd);
+ }
+
+ nsh_output(vtbl, "\n");
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: help_usage
+ ****************************************************************************/
+
+#if !defined(CONFIG_NSH_DISABLE_HELP) && !defined(CONFIG_NSH_HELP_TERSE)
+static inline void help_usage(FAR struct nsh_vtbl_s *vtbl)
+{
+ 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\n");
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: help_showcmd
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_HELP
+static void help_showcmd(FAR struct nsh_vtbl_s *vtbl,
+ FAR const struct cmdmap_s *cmdmap)
+{
+ if (cmdmap->usage)
+ {
+ nsh_output(vtbl, " %s %s\n", cmdmap->cmd, cmdmap->usage);
+ }
+ else
+ {
+ nsh_output(vtbl, " %s\n", cmdmap->cmd);
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: help_cmd
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_HELP
+static int help_cmd(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd)
+{
+ FAR const struct cmdmap_s *cmdmap;
+
+ /* Find the command in the command table */
+
+ for (cmdmap = g_cmdmap; cmdmap->cmd; cmdmap++)
+ {
+ /* Is this the one we are looking for? */
+
+ if (strcmp(cmdmap->cmd, cmd) == 0)
+ {
+ /* Yes... show it */
+
+ nsh_output(vtbl, "%s usage:", cmd);
+ help_showcmd(vtbl, cmdmap);
+ return OK;
+ }
+ }
+
+ nsh_output(vtbl, g_fmtcmdnotfound, cmd);
+ return ERROR;
+}
+#endif
+
+/****************************************************************************
+ * Name: help_allcmds
+ ****************************************************************************/
+
+#if !defined(CONFIG_NSH_DISABLE_HELP) && !defined(CONFIG_NSH_HELP_TERSE)
+static inline void help_allcmds(FAR struct nsh_vtbl_s *vtbl)
+{
+ FAR const struct cmdmap_s *cmdmap;
+
+ /* Show all of the commands in the command table */
+
+ for (cmdmap = g_cmdmap; cmdmap->cmd; cmdmap++)
+ {
+ help_showcmd(vtbl, cmdmap);
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: help_builtins
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_HELP
+static inline void help_builtins(FAR struct nsh_vtbl_s *vtbl)
+{
+#ifdef CONFIG_NSH_BUILTIN_APPS
+ FAR const char *name;
+ int i;
+
+ /* List the set of available built-in commands */
+
+ nsh_output(vtbl, "\nBuiltin Apps:\n");
+ for (i = 0; (name = namedapp_getname(i)) != NULL; i++)
+ {
+ nsh_output(vtbl, " %s\n", name);
+ }
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_help
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_HELP
+static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
+{
+ FAR const char *cmd = NULL;
+#ifndef CONFIG_NSH_HELP_TERSE
+ bool verbose = false;
+ int i;
+#endif
+
+ /* The command may be followed by a verbose option */
+
+#ifndef CONFIG_NSH_HELP_TERSE
+ i = 1;
+ if (argc > i)
+ {
+ if (strcmp(argv[i], "-v") == 0)
+ {
+ verbose = true;
+ i++;
+ }
+ }
+
+ /* The command line may end with a command name */
+
+ if (argc > i)
+ {
+ cmd = argv[i];
+ }
+
+ /* Show the generic usage if verbose is requested */
+
+ if (verbose)
+ {
+ help_usage(vtbl);
+ }
+#else
+ if (argc > 1)
+ {
+ cmd = argv[1];
+ }
+#endif
+
+ /* Are we showing help on a single command? */
+
+ if (cmd)
+ {
+ /* Yes.. show the single command */
+
+ help_cmd(vtbl, cmd);
+ }
+ else
+ {
+ /* In verbose mode, show detailed help for all commands */
+
+#ifndef CONFIG_NSH_HELP_TERSE
+ if (verbose)
+ {
+ nsh_output(vtbl, "Where <cmd> is one of:\n");
+ help_allcmds(vtbl);
+ }
+
+ /* Otherwise, just show the list of command names */
+
+ else
+#endif
+ {
+ help_cmd(vtbl, "help");
+ nsh_output(vtbl, "\n");
+ help_cmdlist(vtbl);
+ }
+
+ /* And show the list of built-in applications */
+
+ help_builtins(vtbl);
+ }
+
+ 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, 0);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nsh_execute
+ *
+ * Description:
+ * Exectue the command in argv[0]
+ *
+ * Returned Value:
+ * <0 If exec_namedapp() fails, then the negated errno value
+ * is returned.
+ * -1 (ERRROR) if the command was unsuccessful
+ * 0 (OK) if the command was successful
+ * 1 if an application task was spawned successfully, but
+ * returned failure exit status.
+ *
+ ****************************************************************************/
+
+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
+ ret = nsh_execapp(vtbl, cmd, argv);
+
+ /* If the built-in application was successfully started, return OK
+ * or 1 (if the application returned a non-zero exit status).
+ */
+
+ if (ret >= 0)
+ {
+ return ret;
+ }
+#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_parse
+ *
+ * Description:
+ * This function parses and executes one NSH command.
+ *
+ ****************************************************************************/
+
+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, &param);
+ 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, &param);
+
+ /* 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. nsh_execute will return:
+ *
+ * -1 (ERRROR) if the command was unsuccessful
+ * 0 (OK) if the command was successful
+ * 1 if an application task was spawned successfully, but
+ * returned failure exit status.
+ */
+
+ 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);
+ }
+
+ /* Treat both errors and non-zero return codes as "errors" so that
+ * it is possible to test for non-zero returns in nsh scripts.
+ */
+
+ if (ret != OK)
+ {
+ 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..487214501
--- /dev/null
+++ b/apps/nshlib/nsh_proccmds.c
@@ -0,0 +1,310 @@
+/****************************************************************************
+ * apps/nshlib/nsh_proccmds.c
+ *
+ * Copyright (C) 2007-2009, 2011-2012 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sched.h>
+#include <errno.h>
+
+#include "nsh.h"
+#include "nsh_console.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..4134b45a3
--- /dev/null
+++ b/apps/nshlib/nsh_romfsetc.c
@@ -0,0 +1,124 @@
+/****************************************************************************
+ * apps/nshlib/nsh_romfsetc.c
+ *
+ * Copyright (C) 2008-2012 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 <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_telnetd.c b/apps/nshlib/nsh_telnetd.c
new file mode 100644
index 000000000..0117aad04
--- /dev/null
+++ b/apps/nshlib/nsh_telnetd.c
@@ -0,0 +1,187 @@
+/****************************************************************************
+ * apps/nshlib/nsh_telnetd.c
+ *
+ * Copyright (C) 2007-2012 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 <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <apps/netutils/telnetd.h>
+
+#include "nsh.h"
+#include "nsh_console.h"
+
+#ifdef CONFIG_NSH_TELNET
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_telnetmain
+ ****************************************************************************/
+
+int nsh_telnetmain(int argc, char *argv[])
+{
+ FAR struct console_stdio_s *pstate = nsh_newconsole();
+ DEBUGASSERT(pstate != NULL);
+
+ dbg("Session [%d] Started\n", getpid());
+
+ /* Present a greeting */
+
+ fputs(g_nshgreeting, pstate->cn_outstream);
+ fflush(pstate->cn_outstream);
+
+ /* Execute the startup script */
+
+#if defined(CONFIG_NSH_ROMFSETC) && !defined(CONFIG_NSH_CONSOLE)
+ (void)nsh_script(&pstate->cn_vtbl, "init", NSH_INITPATH);
+#endif
+
+ /* Then enter the command line parsing loop */
+
+ for (;;)
+ {
+ /* Display the prompt string */
+
+ fputs(g_nshprompt, pstate->cn_outstream);
+ fflush(pstate->cn_outstream);
+
+ /* Get the next line of input from the Telnet client */
+
+ if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL)
+ {
+ /* Parse process the received Telnet command */
+
+ (void)nsh_parse(&pstate->cn_vtbl, pstate->cn_line);
+ fflush(pstate->cn_outstream);
+ }
+ else
+ {
+ fprintf(pstate->cn_outstream, g_fmtcmdfailed, "nsh_telnetmain",
+ "fgets", NSH_ERRNO);
+ nsh_exit(&pstate->cn_vtbl, 1);
+ }
+ }
+
+ /* Clean up */
+
+ nsh_exit(&pstate->cn_vtbl, 0);
+
+ /* We do not get here, but this is necessary to keep some compilers happy */
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_telnetstart
+ *
+ * Description:
+ * nsh_telnetstart() starts the Telnet daemon that will allow multiple
+ * NSH connections via Telnet. This function returns immediately after
+ * the daemon has been started.
+ *
+ * Input Parameters:
+ * None. All of the properties of the Telnet daemon are controlled by
+ * NuttX configuration setting.
+ *
+ * Returned Values:
+ * Zero if the Telnet daemon was successfully started. A negated errno
+ * value will be returned on failure.
+ *
+ ****************************************************************************/
+
+int nsh_telnetstart(void)
+{
+ struct telnetd_config_s config;
+ int ret;
+
+ /* Configure the telnet daemon */
+
+ config.d_port = HTONS(CONFIG_NSH_TELNETD_PORT);
+ config.d_priority = CONFIG_NSH_TELNETD_DAEMONPRIO;
+ config.d_stacksize = CONFIG_NSH_TELNETD_DAEMONSTACKSIZE;
+ config.t_priority = CONFIG_NSH_TELNETD_CLIENTPRIO;
+ config.t_stacksize = CONFIG_NSH_TELNETD_CLIENTSTACKSIZE;
+ config.t_entry = nsh_telnetmain;
+
+ /* Start the telnet daemon */
+
+ vdbg("Starting the Telnet daemon\n");
+ ret = telnetd_start(&config);
+ if (ret < 0)
+ {
+ dbg("Failed to tart the Telnet daemon: %d\n", ret);
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_NSH_TELNET */
diff --git a/apps/nshlib/nsh_test.c b/apps/nshlib/nsh_test.c
new file mode 100644
index 000000000..6e1b65e5f
--- /dev/null
+++ b/apps/nshlib/nsh_test.c
@@ -0,0 +1,438 @@
+/****************************************************************************
+ * apps/nshlib/nsh_test.c
+ *
+ * Copyright (C) 2008, 2011-2012 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.
+ *
+ ****************************************************************************/
+
+/* 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"
+#include "nsh_console.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..bc2bda6f4
--- /dev/null
+++ b/apps/nshlib/nsh_timcmds.c
@@ -0,0 +1,331 @@
+/****************************************************************************
+ * apps/nshlib/dbg_timcmds.c
+ *
+ * Copyright (C) 2011-2012 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "nsh.h"
+#include "nsh_console.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/nsh_usbdev.c b/apps/nshlib/nsh_usbdev.c
new file mode 100644
index 000000000..3d123532a
--- /dev/null
+++ b/apps/nshlib/nsh_usbdev.c
@@ -0,0 +1,243 @@
+/****************************************************************************
+ * apps/nshlib/nsh_usbdev.c
+ *
+ * Copyright (C) 2012 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <debug.h>
+
+#ifdef CONFIG_CDCACM
+# include <nuttx/usb/cdcacm.h>
+#endif
+
+#ifdef CONFIG_CDCACM
+# include <nuttx/usb/pl2303.h>
+#endif
+
+#include "nsh.h"
+
+#ifdef CONFIG_USBDEV
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_DEBUG) || defined(CONFIG_NSH_USBCONSOLE)
+# define trmessage lib_lowprintf
+#else
+# define trmessage printf
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_tracecallback
+ ****************************************************************************/
+
+#ifdef CONFIG_USBDEV_TRACE
+static int nsh_tracecallback(struct usbtrace_s *trace, void *arg)
+{
+ usbtrace_trprintf((trprintf_t)trmessage, trace->event, trace->value);
+ return 0;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_usbconsole
+ ****************************************************************************/
+
+#ifdef HAVE_USB_CONSOLE
+int nsh_usbconsole(void)
+{
+ char inch;
+ ssize_t nbytes;
+ int nlc;
+ int fd;
+ int ret;
+
+ /* Initialize any USB tracing options that were requested */
+
+#ifdef CONFIG_USBDEV_TRACE
+ usbtrace_enable(TRACE_BITSET);
+#endif
+
+ /* Don't start the NSH console until the console device is ready. Chances
+ * are, we get here with no functional console. The USB console will not
+ * be available until the device is connected to the host and until the
+ * host-side application opens the connection.
+ */
+
+ /* Initialize the USB serial driver */
+
+#if defined(CONFIG_PL2303) || defined(CONFIG_CDCACM)
+#ifdef CONFIG_CDCACM
+ ret = cdcacm_initialize(CONFIG_NSH_UBSDEV_MINOR, NULL);
+#else
+ ret = usbdev_serialinitialize(CONFIG_NSH_UBSDEV_MINOR);
+#endif
+ DEBUGASSERT(ret == OK);
+#endif
+
+ /* Open the USB serial device for read/write access */
+
+ do
+ {
+ /* Try to open the console */
+
+ fd = open(CONFIG_NSH_USBCONDEV, O_RDWR);
+ if (fd < 0)
+ {
+ /* ENOTCONN means that the USB device is not yet connected. Anything
+ * else is bad.
+ */
+
+ DEBUGASSERT(errno == ENOTCONN);
+
+ /* Sleep a bit and try again */
+
+ sleep(2);
+ }
+ }
+ while (fd < 0);
+
+ /* Now waiting until we successfully read a carriage return a few times.
+ * That is a sure way of know that there is something at the other end of
+ * the USB serial connection that is ready to talk with us. The user needs
+ * to hit ENTER a few times to get things started.
+ */
+
+ nlc = 0;
+ do
+ {
+ /* Read one byte */
+
+ inch = 0;
+ nbytes = read(fd, &inch, 1);
+
+ /* Is it a carriage return (or maybe a newline)? */
+
+ if (nbytes == 1 && (inch == '\n' || inch == '\r'))
+ {
+ /* Yes.. increment the count */
+
+ nlc++;
+ }
+ else
+ {
+ /* No.. Reset the count. We need to see 3 in a row to continue. */
+
+ nlc = 0;
+ }
+ }
+ while (nlc < 3);
+
+ /* Make sure the stdin, stdout, and stderr are closed */
+
+ (void)fclose(stdin);
+ (void)fclose(stdout);
+ (void)fclose(stderr);
+
+ /* Dup the fd to create standard fd 0-2 */
+
+ (void)dup2(fd, 0);
+ (void)dup2(fd, 1);
+ (void)dup2(fd, 2);
+
+ /* We can close the original file descriptor now (unless it was one of 0-2) */
+
+ if (fd > 2)
+ {
+ close(fd);
+ }
+
+ /* fdopen to get the stdin, stdout and stderr streams. The following logic depends
+ * on the fact that the library layer will allocate FILEs in order. And since
+ * we closed stdin, stdout, and stderr above, that is what we should get.
+ *
+ * fd = 0 is stdin (read-only)
+ * fd = 1 is stdout (write-only, append)
+ * fd = 2 is stderr (write-only, append)
+ */
+
+ (void)fdopen(0, "r");
+ (void)fdopen(1, "a");
+ (void)fdopen(2, "a");
+ return OK;
+}
+
+#endif /* HAVE_USB_CONSOLE */
+
+/****************************************************************************
+ * Name: nsh_usbtrace
+ ****************************************************************************/
+
+#if defined(CONFIG_USBDEV_TRACE) && defined(HAVE_USB_CONSOLE)
+void nsh_usbtrace(void)
+{
+ (void)usbtrace_enumerate(nsh_tracecallback, NULL);
+}
+#endif
+
+#endif /* CONFIG_USBDEV */
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/Kconfig b/apps/system/Kconfig
new file mode 100644
index 000000000..44bf5a2e6
--- /dev/null
+++ b/apps/system/Kconfig
@@ -0,0 +1,20 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+menu "Custom free memory command"
+source "$APPSDIR/system/free/Kconfig"
+endmenu
+
+menu "I2C tool"
+source "$APPSDIR/system/i2c/Kconfig"
+endmenu
+
+menu "FLASH Program Installation"
+source "$APPSDIR/system/install/Kconfig"
+endmenu
+
+menu "readline() support"
+source "$APPSDIR/system/readline/Kconfig"
+endmenu
diff --git a/apps/system/Make.defs b/apps/system/Make.defs
new file mode 100644
index 000000000..a4aea2d31
--- /dev/null
+++ b/apps/system/Make.defs
@@ -0,0 +1,51 @@
+############################################################################
+# apps/system/Make.defs
+# Adds selected applications to apps/ build
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_SYSTEM_FREE),y)
+CONFIGURED_APPS += system/free
+endif
+
+ifeq ($(CONFIG_SYSTEM_I2CTOOL),y)
+CONFIGURED_APPS += system/i2c
+endif
+
+ifeq ($(CONFIG_SYSTEM_INSTALL),y)
+CONFIGURED_APPS += system/install
+endif
+
+ifeq ($(CONFIG_SYSTEM_READLINE),y)
+CONFIGURED_APPS += system/readline
+endif
diff --git a/apps/system/Makefile b/apps/system/Makefile
new file mode 100644
index 000000000..a0eb5dfde
--- /dev/null
+++ b/apps/system/Makefile
@@ -0,0 +1,70 @@
+############################################################################
+# apps/system/Makefile
+#
+# Copyright (C) 2011-2012 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 containing system task
+
+SUBDIRS = free i2c install readline
+
+# 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/Kconfig b/apps/system/free/Kconfig
new file mode 100644
index 000000000..239559867
--- /dev/null
+++ b/apps/system/free/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config SYSTEM_FREE
+ bool "NSH free command replacement"
+ default n
+ ---help---
+ Enable support for the NSH free replacement command.
+
+if SYSTEM_FREE
+endif
+
diff --git a/apps/system/free/Makefile b/apps/system/free/Makefile
new file mode 100644
index 000000000..7f911d81c
--- /dev/null
+++ b/apps/system/free/Makefile
@@ -0,0 +1,114 @@
+############################################################################
+# apps/system/free/Makefile
+#
+# Copyright (C) 2011 Uros Platise. All rights reserved.
+# Author: Uros Platise <uros.platise@isotel.eu>
+# 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.
+#
+############################################################################
+
+# 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)
+
+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/free/README.txt b/apps/system/free/README.txt
new file mode 100644
index 000000000..1c2d380d4
--- /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 <gnutt@nuttx.org>
+ Date: 17. March 2011
diff --git a/apps/system/free/free.c b/apps/system/free/free.c
new file mode 100644
index 000000000..3d9698ecb
--- /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 <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 <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/Kconfig b/apps/system/i2c/Kconfig
new file mode 100644
index 000000000..745378b37
--- /dev/null
+++ b/apps/system/i2c/Kconfig
@@ -0,0 +1,61 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+
+config SYSTEM_I2CTOOL
+ bool "I2C tool"
+ default n
+ depends on I2C
+ ---help---
+ Enable support for the I2C tool.
+
+config I2CTOOL_BUILTIN
+ bool "NSH built-in command"
+ default y
+ depends on SYSTEM_I2CTOOL && NSH_BUILTIN_APPS
+ ---help---
+ Build the tools as an NSH built-in command
+
+config I2CTOOL_MINBUS
+ int "Minimum bus number"
+ default 0
+ depends on SYSTEM_I2CTOOL
+ ---help---
+ Smallest bus index supported by the hardware (default 0).
+
+config I2CTOOL_MAXBUS
+ int "Maximum bus number"
+ depends on SYSTEM_I2CTOOL
+ default 3
+ ---help---
+ Largest bus index supported by the hardware (default 3)
+
+config I2CTOOL_MINADDR
+ hex "Minimum I2C address"
+ depends on SYSTEM_I2CTOOL
+ default 0x03
+ ---help---
+ Minium 7-bit device address (default: 0x03)
+
+config I2CTOOL_MAXADDR
+ hex "Maximum I2C address"
+ depends on SYSTEM_I2CTOOL
+ default 0x77
+ ---help---
+ Largest 7-bit device address (default: 0x77)
+
+config I2CTOOL_MAXREGADDR
+ hex "Maximum I2C register address"
+ default 0xff
+ depends on SYSTEM_I2CTOOL
+ ---help---
+ Largest I2C register address (default: 0xff)
+
+config I2CTOOL_DEFFREQ
+ int "Default I2C frequency"
+ default 4000000
+ depends on SYSTEM_I2CTOOL
+ ---help---
+ Default I2C frequency (default: 4000000)
diff --git a/apps/system/i2c/Makefile b/apps/system/i2c/Makefile
new file mode 100644
index 000000000..845c149f6
--- /dev/null
+++ b/apps/system/i2c/Makefile
@@ -0,0 +1,102 @@
+############################################################################
+# apps/system/i2c
+#
+# Copyright (C) 2011-2012 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
+
+# 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 100644
index 000000000..7b432533b
--- /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
+discuss 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..a684166ff
--- /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 <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 <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..4af648c7d
--- /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 <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 <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..3d0480a15
--- /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 <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 <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 = &regaddr;
+ 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..08510af4b
--- /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 <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 <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 = &regaddr;
+ 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..0cf6786cb
--- /dev/null
+++ b/apps/system/i2c/i2c_main.c
@@ -0,0 +1,446 @@
+/****************************************************************************
+ * apps/system/i2c/i2c_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 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
+ ****************************************************************************/
+
+int i2c_main(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..5baf7f835
--- /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 <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 <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 = &regaddr;
+ 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..109e9c4ce
--- /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 <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 <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..4ff26d03e
--- /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 <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.
+ *
+ ****************************************************************************/
+
+#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/Kconfig b/apps/system/install/Kconfig
new file mode 100644
index 000000000..a48f67f20
--- /dev/null
+++ b/apps/system/install/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config SYSTEM_INSTALL
+ bool "FLASH installation tool"
+ default n
+ ---help---
+ Enable support for the FLASH installation tool.
+
+if SYSTEM_INSTALL
+endif
+
diff --git a/apps/system/install/Makefile b/apps/system/install/Makefile
new file mode 100644
index 000000000..71d82f34c
--- /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 <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.
+#
+############################################################################
+
+# 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 100644
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 100644
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/system/readline/Kconfig b/apps/system/readline/Kconfig
new file mode 100644
index 000000000..6482b1204
--- /dev/null
+++ b/apps/system/readline/Kconfig
@@ -0,0 +1,22 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config SYSTEM_READLINE
+ bool "readline() support"
+ default n
+ ---help---
+ Enable support for the readline() function.
+
+if SYSTEM_READLINE
+config READLINE_ECHO
+ bool "Echo character input"
+ default y
+ ---help---
+ Echo received character input back via stdout. This is normal
+ behavior and should be selected unless the source of stdin input
+ already has local echo support or you need to suppress the back-channel
+ responses for any other reason.
+
+endif
diff --git a/apps/system/readline/Makefile b/apps/system/readline/Makefile
new file mode 100644
index 000000000..34fab7e81
--- /dev/null
+++ b/apps/system/readline/Makefile
@@ -0,0 +1,103 @@
+############################################################################
+# apps/system/readline/Makefile
+#
+# Copyright (C) 2012 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
+
+ifeq ($(WINTOOL),y)
+INCDIROPT = -w
+endif
+
+# The Readline Library
+
+ASRCS =
+CSRCS = readline.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
+
+# Context build phase target
+
+context:
+
+# Dependency build phase target
+
+.depend: Makefile $(SRCS)
+ @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
+ @touch $@
+
+depend: .depend
+
+# Housekeeping targets
+
+clean:
+ @rm -f *.o *~ .*.swp .built
+ $(call CLEAN)
+
+distclean: clean
+ @rm -f .context Make.dep .depend
+
+-include Make.dep
diff --git a/apps/system/readline/readline.c b/apps/system/readline/readline.c
new file mode 100644
index 000000000..ec2dc1c0a
--- /dev/null
+++ b/apps/system/readline/readline.c
@@ -0,0 +1,404 @@
+/****************************************************************************
+ * lib/stdio/lib_fgets.c
+ *
+ * Copyright (C) 2007-2008, 2011-2012 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 <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/ascii.h>
+#include <nuttx/vt100.h>
+
+#include <apps/readline.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* In some systems, the underlying serial logic may automatically echo
+ * characters back to the console. We will assume that that is not the case
+ & here
+ */
+
+#define CONFIG_READLINE_ECHO 1
+
+/* Some environments may return CR as end-of-line, others LF, and others
+ * both. If not specified, the logic here assumes either (but not both) as
+ * the default.
+ */
+
+#if defined(CONFIG_EOL_IS_CR)
+# undef CONFIG_EOL_IS_LF
+# undef CONFIG_EOL_IS_BOTH_CRLF
+# undef CONFIG_EOL_IS_EITHER_CRLF
+#elif defined(CONFIG_EOL_IS_LF)
+# undef CONFIG_EOL_IS_CR
+# undef CONFIG_EOL_IS_BOTH_CRLF
+# undef CONFIG_EOL_IS_EITHER_CRLF
+#elif defined(CONFIG_EOL_IS_BOTH_CRLF)
+# undef CONFIG_EOL_IS_CR
+# undef CONFIG_EOL_IS_LF
+# undef CONFIG_EOL_IS_EITHER_CRLF
+#elif defined(CONFIG_EOL_IS_EITHER_CRLF)
+# undef CONFIG_EOL_IS_CR
+# undef CONFIG_EOL_IS_LF
+# undef CONFIG_EOL_IS_BOTH_CRLF
+#else
+# undef CONFIG_EOL_IS_CR
+# undef CONFIG_EOL_IS_LF
+# undef CONFIG_EOL_IS_BOTH_CRLF
+# define CONFIG_EOL_IS_EITHER_CRLF 1
+#endif
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+/* <esc>[K is the VT100 command erases to the end of the line. */
+
+static const char g_erasetoeol[] = VT100_CLEAREOL;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: readline_rawgetc
+ ****************************************************************************/
+
+static inline int readline_rawgetc(int infd)
+{
+ char buffer;
+ ssize_t nread;
+
+ /* Loop until we successfully read a character (or until an unexpected
+ * error occurs).
+ */
+
+ do
+ {
+ /* Read one character from the incoming stream */
+
+ nread = read(infd, &buffer, 1);
+
+ /* Return EOF if the end of file (0) or error (-1) occurs. */
+
+ if (nread < 1)
+ {
+ /* EINTR is not really an error; it simply means that a signal we
+ * received while watiing for intput.
+ */
+
+ if (nread == 0 || errno != EINTR)
+ {
+ return EOF;
+ }
+ }
+ }
+ while (nread < 1);
+
+ /* On success, returnt he character that was read */
+
+ return (int)buffer;
+}
+
+/****************************************************************************
+ * Name: readline_consoleputc
+ ****************************************************************************/
+
+#ifdef CONFIG_READLINE_ECHO
+static inline void readline_consoleputc(int ch, int outfd)
+{
+ char buffer = ch;
+ ssize_t nwritten;
+
+ /* Loop until we successfully write a character (or until an unexpected
+ * error occurs).
+ */
+
+ do
+ {
+ /* Write the character to the outgoing stream */
+
+ nwritten = write(outfd, &buffer, 1);
+
+ /* Check for irrecoverable write errors. */
+
+ if (nwritten < 0 && errno != EINTR)
+ {
+ break;
+ }
+ }
+ while (nwritten < 1);
+}
+#endif
+
+/****************************************************************************
+ * Name: readline_consolewrite
+ ****************************************************************************/
+
+#ifdef CONFIG_READLINE_ECHO
+static inline void readline_consolewrite(int outfd, FAR const char *buffer, size_t buflen)
+{
+ (void)write(outfd, buffer, buflen);
+}
+#endif
+
+/****************************************************************************
+ * Global Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: readline
+ *
+ * readline() reads in at most one less than 'buflen' characters from
+ * 'instream' and stores them into the buffer pointed to by 'buf'.
+ * Characters are echoed on 'outstream'. Reading stops after an EOF or a
+ * newline. If a newline is read, it is stored into the buffer. A null
+ * terminator is stored after the last character in the buffer.
+ *
+ * This version of realine assumes that we are reading and writing to
+ * a VT100 console. This will not work well if 'instream' or 'outstream'
+ * corresponds to a raw byte steam.
+ *
+ * This function is inspired by the GNU readline but is an entirely
+ * different creature.
+ *
+ * Input Parameters:
+ * buf - The user allocated buffer to be filled.
+ * buflen - the size of the buffer.
+ * instream - The stream to read characters from
+ * outstream - The stream to each characters to.
+ *
+ * Returned values:
+ * On success, the (positive) number of bytes transferred is returned.
+ * A length of zero would indicate an end of file condition. On failure,
+ * a negated errno value is returned.
+ *
+ **************************************************************************/
+
+ssize_t readline(FAR char *buf, int buflen, FILE *instream, FILE *outstream)
+{
+ int infd;
+ int outfd;
+ int escape;
+ int nch;
+
+ /* Sanity checks */
+
+ if (!instream || !outstream || !buf || buflen < 1)
+ {
+ return -EINVAL;
+ }
+
+ if (buflen < 2)
+ {
+ *buf = '\0';
+ return 0;
+ }
+
+ /* Extract the file descriptions. This is cheating (and horribly non-
+ * standard)
+ */
+
+ infd = instream->fs_filedes;
+ outfd = outstream->fs_filedes;
+
+ /* <esc>[K is the VT100 command that erases to the end of the line. */
+
+#ifdef CONFIG_READLINE_ECHO
+ readline_consolewrite(outfd, g_erasetoeol, sizeof(g_erasetoeol));
+#endif
+
+ /* Read characters until we have a full line. On each the loop we must
+ * be assured that there are two free bytes in the line buffer: One for
+ * the next character and one for the null terminator.
+ */
+
+ escape = 0;
+ nch = 0;
+
+ for(;;)
+ {
+ /* Get the next character */
+
+ int ch = readline_rawgetc(infd);
+
+ /* Are we processing a VT100 escape sequence */
+
+ if (escape)
+ {
+ /* Yes, is it an <esc>[, 3 byte sequence */
+
+ if (ch != ASCII_LBRACKET || escape == 2)
+ {
+ /* We are finished with the escape sequence */
+
+ escape = 0;
+ ch = 'a';
+ }
+ else
+ {
+ /* The next character is the end of a 3-byte sequence.
+ * NOTE: Some of the <esc>[ sequences are longer than
+ * 3-bytes, but I have not encountered any in normal use
+ * yet and, so, have not provided the decoding logic.
+ */
+
+ escape = 2;
+ }
+ }
+
+ /* Check for backspace
+ *
+ * There are several notions of backspace, for an elaborate summary see
+ * http://www.ibb.net/~anne/keyboard.html. There is no clean solution.
+ * Here both DEL and backspace are treated like backspace here. The
+ * Unix/Linux screen terminal by default outputs DEL (0x7f) when the
+ * backspace key is pressed.
+ */
+
+ else if (ch == ASCII_BS || ch == ASCII_DEL)
+ {
+ /* Eliminate that last character in the buffer. */
+
+ if (nch > 0)
+ {
+ nch--;
+
+#ifdef CONFIG_READLINE_ECHO
+ /* Echo the backspace character on the console. Always output
+ * the backspace character because the VT100 terminal doesn't
+ * understand DEL properly.
+ */
+
+ readline_consoleputc(ASCII_BS, outfd);
+ readline_consolewrite(outfd, g_erasetoeol, sizeof(g_erasetoeol));
+#endif
+ }
+ }
+
+ /* Check for the beginning of a VT100 escape sequence */
+
+ else if (ch == ASCII_ESC)
+ {
+ /* The next character is escaped */
+
+ escape = 1;
+ }
+
+ /* Check for end-of-line. This is tricky only in that some
+ * environments may return CR as end-of-line, others LF, and
+ * others both.
+ */
+
+#if defined(CONFIG_EOL_IS_LF) || defined(CONFIG_EOL_IS_BOTH_CRLF)
+ else if (ch == '\n')
+#elif defined(CONFIG_EOL_IS_CR)
+ else if (ch == '\r')
+#elif CONFIG_EOL_IS_EITHER_CRLF
+ else if (ch == '\n' || ch == '\r')
+#endif
+ {
+ /* The newline is stored in the buffer along with the null
+ * terminator.
+ */
+
+ buf[nch++] = '\n';
+ buf[nch] = '\0';
+
+#ifdef CONFIG_READLINE_ECHO
+ /* Echo the newline to the console */
+
+ readline_consoleputc('\n', outfd);
+#endif
+ return nch;
+ }
+
+ /* Check for end-of-file */
+
+ else if (ch == EOF)
+ {
+ /* Terminate the line (which might be zero length) */
+
+ buf[nch] = '\0';
+ return nch;
+ }
+
+ /* Otherwise, check if the character is printable and, if so, put the
+ * character in the line buffer
+ */
+
+ else if (isprint(ch))
+ {
+ buf[nch++] = ch;
+
+#ifdef CONFIG_READLINE_ECHO
+ /* Echo the character to the console */
+
+ readline_consoleputc(ch, outfd);
+#endif
+ /* Check if there is room for another character and the line's
+ * null terminator. If not then we have to end the line now.
+ */
+
+ if (nch + 1 >= buflen)
+ {
+ buf[nch] = '\0';
+ return nch;
+ }
+ }
+ }
+}
+
diff --git a/apps/vsn/Kconfig b/apps/vsn/Kconfig
new file mode 100644
index 000000000..1f0c25f16
--- /dev/null
+++ b/apps/vsn/Kconfig
@@ -0,0 +1,11 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+comment "VSN board add-ons"
+
+source "$APPSDIR/vsn/poweroff/Kconfig"
+source "$APPSDIR/vsn/ramtron/Kconfig"
+source "$APPSDIR/vsn/sdcard/Kconfig"
+source "$APPSDIR/vsn/sysinfo/Kconfig"
diff --git a/apps/vsn/Make.defs b/apps/vsn/Make.defs
new file mode 100644
index 000000000..6d59ab838
--- /dev/null
+++ b/apps/vsn/Make.defs
@@ -0,0 +1,51 @@
+############################################################################
+# apps/vsn/Make.defs
+# Adds selected applications to apps/ build
+#
+# Copyright (C) 2012 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.
+#
+############################################################################
+
+ifeq ($(CONFIG_VSN_POWEROFF),y)
+CONFIGURED_APPS += vsn/poweroff
+endif
+
+ifeq ($(CONFIG_VSN_RAMTRON),y)
+CONFIGURED_APPS += vsn/ramtron
+endif
+
+ifeq ($(CONFIG_VSN_SDCARD),y)
+CONFIGURED_APPS += vsn/sdcard
+endif
+
+ifeq ($(CONFIG_VSN_SYSINFO),y)
+CONFIGURED_APPS += vsn/sysinfo
+endif
diff --git a/apps/vsn/Makefile b/apps/vsn/Makefile
new file mode 100644
index 000000000..21901d96d
--- /dev/null
+++ b/apps/vsn/Makefile
@@ -0,0 +1,71 @@
+############################################################################
+# apps/vsn/Makefile
+#
+# Copyright (C) 2011-2012 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 = 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/poweroff/Kconfig b/apps/vsn/poweroff/Kconfig
new file mode 100644
index 000000000..d0059a0d3
--- /dev/null
+++ b/apps/vsn/poweroff/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config VSN_POWEROFF
+ bool "NSH poweroff command"
+ default n
+ ---help---
+ Enable support for the NSH poweroff command.
+
+if VSN_POWEROFF
+endif
+
diff --git a/apps/vsn/poweroff/Makefile b/apps/vsn/poweroff/Makefile
new file mode 100644
index 000000000..e58ecfa86
--- /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 <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.
+#
+############################################################################
+
+# 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/Kconfig b/apps/vsn/ramtron/Kconfig
new file mode 100644
index 000000000..14f358921
--- /dev/null
+++ b/apps/vsn/ramtron/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config VSN_RAMTRON
+ bool "NSH ramtron command"
+ default n
+ ---help---
+ Enable support for the NSH ramtron command.
+
+if VSN_RAMTRON
+endif
+
diff --git a/apps/vsn/ramtron/Makefile b/apps/vsn/ramtron/Makefile
new file mode 100644
index 000000000..d930aa92c
--- /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 <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.
+#
+############################################################################
+
+# 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..f1e8db100
--- /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 <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 <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/Kconfig b/apps/vsn/sdcard/Kconfig
new file mode 100644
index 000000000..8e6c13264
--- /dev/null
+++ b/apps/vsn/sdcard/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config VSN_SDCARD
+ bool "NSH sdcard command"
+ default n
+ ---help---
+ Enable support for the NSH sdcard command.
+
+if VSN_SDCARD
+endif
+
diff --git a/apps/vsn/sdcard/Makefile b/apps/vsn/sdcard/Makefile
new file mode 100644
index 000000000..213021b25
--- /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 <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.
+#
+############################################################################
+
+# 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..a81e8432a
--- /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 <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 <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/Kconfig b/apps/vsn/sysinfo/Kconfig
new file mode 100644
index 000000000..38e0f16be
--- /dev/null
+++ b/apps/vsn/sysinfo/Kconfig
@@ -0,0 +1,14 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config VSN_SYSINFO
+ bool "NSH sysinfo command"
+ default n
+ ---help---
+ Enable support for the NSH sysinfo command.
+
+if VSN_SYSINFO
+endif
+
diff --git a/apps/vsn/sysinfo/Makefile b/apps/vsn/sysinfo/Makefile
new file mode 100644
index 000000000..b4afc8a97
--- /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 <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.
+#
+############################################################################
+
+# 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;
+}