mirror of
https://github.com/apache/nuttx.git
synced 2025-01-12 22:08:35 +08:00
Doc: improve and add documentations for the guide section of the wiki
Some checks failed
Build Documentation / build-html (push) Has been cancelled
Some checks failed
Build Documentation / build-html (push) Has been cancelled
* Add a migration warning to the update release system and the elf programs documentation pages. This is just to add a papertrail from where the documentation originate in case of error during the migration process. * Improve the building nuttx with app out of source tree * Add new guide pages * Building uclibc++ * Custom app directories * Debugging ELF loadable modules * Multiple NSH sessions * NSH network link management * RAM & ROM disks * Reading CAN messages * Remove device drivers with NSH
This commit is contained in:
parent
dc82a296f7
commit
c55c2511ad
13 changed files with 1045 additions and 1 deletions
207
Documentation/guides/building_nuttx_with_app_out_of_src_tree.rst
Normal file
207
Documentation/guides/building_nuttx_with_app_out_of_src_tree.rst
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
========================================================
|
||||||
|
Building NuttX with Applications Outside the Source Tree
|
||||||
|
========================================================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/display/NUTTX/Building+NuttX+with+Applications+Outside+of+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 approaches:
|
||||||
|
============================
|
||||||
|
|
||||||
|
1. Make export
|
||||||
|
--------------
|
||||||
|
|
||||||
|
There is a make target called ``make export``. It will build NuttX, then bundle
|
||||||
|
all of the header files, libraries, startup objects, and other build components
|
||||||
|
into a ``.zip`` file. You can move that ``.zip`` file into any build environment
|
||||||
|
you want. You can even build NuttX under a DOS CMD window.
|
||||||
|
|
||||||
|
This ``make target`` is documented in the top-level
|
||||||
|
:doc:`Legacy README </introduction/resources>`. Search for ``Build Targets``
|
||||||
|
|
||||||
|
|
||||||
|
1. Replace the apps/ Directory
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
You can replace the entire ``apps/`` directory. It is not a critical part of the
|
||||||
|
OS. The ``apps/`` is simply provided for you to help with your application
|
||||||
|
development. It should not dictate anything that you do.
|
||||||
|
|
||||||
|
To use a different ``apps`` directory, simply execute ``make menuconfig`` in the
|
||||||
|
top-level ``nuttx/`` directory and redefine ``CONFIG_APPS_DIR`` in your
|
||||||
|
``.config`` file so that it points to a different, custom application directory.
|
||||||
|
Note that ``CONFIG_APPS_DIR`` is a `relative` path from the top-level
|
||||||
|
``nuttx/`` 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
|
||||||
|
the `NuttX Porting Guide <https://cwiki.apache.org/confluence/display/NUTTX/Porting+Guide>`_
|
||||||
|
and in the `apps/README.md <https://github.com/apache/nuttx-apps/blob/master/README.md>`_ file.
|
||||||
|
|
||||||
|
1. Extend the apps/ Directory
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
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 do that too: Create a symbolic link in the
|
||||||
|
``apps/`` directory that redirects to your application sub-directory (or copy
|
||||||
|
your code into a sub-directory of ``apps/``).
|
||||||
|
|
||||||
|
.. image:: image/custom_app_dir_through_extension.png
|
||||||
|
|
||||||
|
Makefile and Make.defs
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
In order to be incorporated into the build, the directory that you link under
|
||||||
|
the ``apps/`` directory should contain:
|
||||||
|
|
||||||
|
1. A ``Makefile`` that supports the ``clean`` and ``distclean`` targets (see
|
||||||
|
other Makefiles for examples).
|
||||||
|
2. A tiny ``Make.defs`` make file fragment that simply adds the build
|
||||||
|
directories to the variable ``CONFIGURED_APPS`` like:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
CONFIGURED_APPS += my_directory1 my_directory2
|
||||||
|
|
||||||
|
Automatic Sub-directory Inclusion
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The ``apps/Makefile`` will always automatically check for the existence of
|
||||||
|
sub-directories containing a ``Makefile`` and a ``Make.defs`` file. The
|
||||||
|
``Makefile`` will be used only to support cleaning operations. The
|
||||||
|
``Make.defs`` file provides the set of relative paths to directories to be
|
||||||
|
built; these directories must also contain a ``Makefile``. That ``Makefile`` can
|
||||||
|
build the sources and add the object files to the ``apps/libapps.a`` archive
|
||||||
|
(see other Makefiles for examples). It should support the ``all``, ``install``,
|
||||||
|
``context``, and ``depend`` targets.
|
||||||
|
|
||||||
|
``apps/Makefile`` does not depend on any hard-coded lists of directories.
|
||||||
|
Instead, it does a wildcard search to find all appropriate directories. This
|
||||||
|
means that to install a new application, you simply have to copy the directory
|
||||||
|
(or link it) into the ``apps/`` directory. If the new directory includes a
|
||||||
|
``Makefile`` and a ``Make.defs`` file, then it will be automatically discovered
|
||||||
|
and included in the build at ``make`` time.
|
||||||
|
|
||||||
|
Kconfig
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
If the directory that you add also includes a ``Kconfig`` file, then it will be
|
||||||
|
automatically included in the NuttX configuration system as well.
|
||||||
|
``apps/Makefile`` uses a tool at ``apps/tools/mkkconfig.sh`` that dynamically
|
||||||
|
builds the ``apps/Kconfig`` file at pre-configuration time.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The native Windows build will use a corresponding tool called
|
||||||
|
``apps/tools/mkconfig.bat``.
|
||||||
|
|
||||||
|
Install script
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
You could, for example, create a script called ``install.sh`` that installs a
|
||||||
|
custom application, configuration, and board-specific directory:
|
||||||
|
|
||||||
|
1. Copy ``MyBoard`` directory to ``boards/MyBoard``.
|
||||||
|
2. Add a symbolic link to ``MyApplication`` at ``apps/external``
|
||||||
|
3. Configure NuttX:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
tools/configure.sh MyBoard:MyConfiguration
|
||||||
|
|
||||||
|
Special ``apps/external`` Directory
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Use of the name ``apps/external`` is suggested because that name is included in
|
||||||
|
the ``.gitignore`` file and will save you some nuisance when working with GIT.
|
||||||
|
|
||||||
|
4. Contain the apps/ Directory
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
A simple, minimally invasive approach would be to contain the ``apps/`` GIT
|
||||||
|
clone within your custom application directory. In this case, ``apps/`` would
|
||||||
|
appear as a directory under your custom application directory instead of your
|
||||||
|
application directories being inserted as sub-directories of ``apps/``. It may
|
||||||
|
even be implemented as a sub-module of your custom application directory.
|
||||||
|
|
||||||
|
.. image:: image/custom_app_dir_through_containment.png
|
||||||
|
|
||||||
|
Kconfig and Makefile
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
There are only a few minimal requirements of your custom application directory.
|
||||||
|
It needs to have only its own ``Makefile`` and ``Kconfig`` file. That
|
||||||
|
``Kconfig`` would need to include the ``apps/Kconfig``. The ``Makefile`` would
|
||||||
|
similarly need to invoke the ``apps/Makefile`` for all of the relevant build
|
||||||
|
targets. For example, the ``clean`` target:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$(MAKE) -c apps clean TOPDIR=$(TOPDIR)
|
||||||
|
|
||||||
|
Library Issues
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The contained directory will create and install a static library called
|
||||||
|
``libapps($LIBEXT)`` in the ``nuttx/staging`` directory. Your custom logic must
|
||||||
|
also appear in the ``nuttx/staging`` directory. Here are two ways that you might
|
||||||
|
do that:
|
||||||
|
|
||||||
|
1. **Merge with ``libapps($LIBEXT)``.**
|
||||||
|
The custom application directory's ``Makefile`` could create and install the
|
||||||
|
final ``libapps($LIBEXT)`` in the ``nuttx/staging`` directory.
|
||||||
|
``<custom-dir>/apps/libapps($LIBEXT)`` could merge its custom object files
|
||||||
|
with ``<custom-dir>/libapps($LIBEXT)`` and then re-install the library at
|
||||||
|
``nuttx/staging``.
|
||||||
|
2. **Use the EXTRA_LIBS Feature.**
|
||||||
|
The build system supports two special make-related variables called
|
||||||
|
``EXTRA_LIBS`` and ``EXTRA_LIBPATHS``. These may be defined in your
|
||||||
|
board-specific ``Make.defs`` file. ``EXTRA_LIBS`` provides the name of your
|
||||||
|
custom library. If you create ``<custom-dir>/libcustom.a``, then the value
|
||||||
|
of ``EXTRA_LIBS`` would be ``-lcustom`` and the value of ``EXTRA_LIBPATHS``
|
||||||
|
would be ``-L <custom-dir>`` (assuming the GNU ld linker).
|
||||||
|
|
||||||
|
Relative Effort and Benefits
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The contained ``apps/`` directory approach requires some more effort than the
|
||||||
|
extended ``apps/`` approach, but has the advantage that there will be no strange
|
||||||
|
behavior due to issues with ``.gitignore`` and, hence, a cleaner user
|
||||||
|
experience.
|
||||||
|
|
||||||
|
Out-of-tree Builds
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This configuration also has the possibility of supporting out-of-tree builds
|
||||||
|
using ``fusefs``. Suppose, for example, that you have a project directory with
|
||||||
|
the contained ``apps/`` directory and, say, three platform build directories.
|
||||||
|
Using ``fusefs``, you can overlay one of the platform build directories on top
|
||||||
|
of the project directory. Then all files generated by the build will be written
|
||||||
|
into the overlaid platform build directory. When the ``fusefs`` is torn down,
|
||||||
|
the project directory will still be clean, and the build result will still be in
|
||||||
|
the platform build directory. This can then be repeated for the other two
|
||||||
|
platform build directories.
|
||||||
|
|
||||||
|
In this case, you would probably also want to contain the ``nuttx/`` directory
|
||||||
|
in the project directory as well so that the entire system is built out-of-tree.
|
||||||
|
|
||||||
|
Hooking External Applications into the Configuration System
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
Suppose you have opted to extend the ``apps/`` directory with your custom
|
||||||
|
external application directories and would also like to support configuration
|
||||||
|
variables in your external application. No problem! Thanks to Sebastien Lorquet,
|
||||||
|
any external application that you install into the ``apps/`` (whether via a
|
||||||
|
symbolic link or via a directory copy) `will` be included in the NuttX
|
||||||
|
configuration system.
|
||||||
|
|
||||||
|
The top-level ``Kconfig`` file in the ``apps/`` directory is automatically
|
||||||
|
generated based on the contents of each ``apps/`` sub-directory. If your
|
||||||
|
installed sub-directory contains ``Kconfig``, ``Makefile``, and ``Make.defs``
|
||||||
|
files, then it will be incorporated into the NuttX configuration system when the
|
||||||
|
top-level ``Kconfig`` file is generated.
|
84
Documentation/guides/building_uclibcpp.rst
Normal file
84
Documentation/guides/building_uclibcpp.rst
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
=================
|
||||||
|
Building uClibc++
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=139629550
|
||||||
|
and is probably outdated
|
||||||
|
|
||||||
|
A version of `uClibc++ <http://cxx.uclibc.org/>`_ has been ported to NuttX and is available in the NuttX
|
||||||
|
uClibc++ GIT repository at `Bitbucket.org <https://bitbucket.org/nuttx/uclibc/>`_ . This version of uClibc++ was
|
||||||
|
adapted for NuttX by the RGMP team.
|
||||||
|
|
||||||
|
This custom version of uClibc++ resides in the NuttX repository at:
|
||||||
|
|
||||||
|
https://bitbucket.org/nuttx/uclibc/
|
||||||
|
|
||||||
|
rather than in the main NuttX source tree, due to licensing issues: NuttX is
|
||||||
|
licensed under the permissive, modified BSD License; uClibc++, on the other
|
||||||
|
hand, is licensed under the stricter GNU LGPL Version 3 license.
|
||||||
|
|
||||||
|
General build instructions are available in the uClibc++ `README.txt <https://bitbucket.org/nuttx/uclibc/src/master/README.txt>`_
|
||||||
|
file. Those instructions are not repeated here. This page documents specific
|
||||||
|
issues encountered when building this NuttX version of uClibc++ and how they
|
||||||
|
are resolved.
|
||||||
|
|
||||||
|
Undefined Reference to ``_impure_ptr``
|
||||||
|
======================================
|
||||||
|
|
||||||
|
**Problem**
|
||||||
|
|
||||||
|
When building uClibc++, you may encounter an undefined reference to
|
||||||
|
``_impure_ptr`` similar to:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
LD: nuttx
|
||||||
|
.../arm-none-eabi/lib/armv7e-m\libsupc++.a(vterminate.o): In function
|
||||||
|
`__gnu_cxx::__verbose_terminate_handler()`:
|
||||||
|
vterminate.cc:(.text._ZN9__gnu_cxx27__verbose_terminate_handlerEv+0xfc):
|
||||||
|
undefined reference to `_impure_ptr'
|
||||||
|
|
||||||
|
**Solution**
|
||||||
|
|
||||||
|
A definitive, elegant solution is not known, but the following workaround has
|
||||||
|
proven to work:
|
||||||
|
|
||||||
|
1. Locate the directory where you can find ``libsupc++``:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -print-file-name=libsupc++.a
|
||||||
|
|
||||||
|
2. Go to that directory and save a copy of ``vterminate.o`` (in case you need
|
||||||
|
it later):
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
cd <the-directory-containing-libsupc++.a>
|
||||||
|
arm-none-eabi-ar.exe -x libsupc++.a vterminate.o
|
||||||
|
|
||||||
|
3. Remove ``vterminate.o`` from the library. At build time, the uClibc++
|
||||||
|
package will provide a usable replacement:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
arm-none-eabi-ar.exe -d libsupc++.a vterminate.o
|
||||||
|
|
||||||
|
4. At this point, NuttX should link with no problem. If you ever want to
|
||||||
|
restore the original ``vterminate.o`` to ``libsupc++.a``, you can do so
|
||||||
|
by running:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
arm-none-eabi-ar.exe rcs libsupc++.a vterminate.o
|
||||||
|
|
||||||
|
After removing ``vterminate.o`` from the standard library, the
|
||||||
|
uClibc++-provided ``vterminate.o`` becomes the active implementation and
|
||||||
|
prevents references to ``_impure_ptr`` from arising during linkage.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Always exercise caution when modifying toolchain libraries. This
|
||||||
|
workaround is known to be effective but it replaces standard library
|
||||||
|
objects, which may have side effects in other toolchain usage scenarios.
|
165
Documentation/guides/custom_app_directories.rst
Normal file
165
Documentation/guides/custom_app_directories.rst
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
===========================================
|
||||||
|
Custom Application Directories
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/display/NUTTX/Custom+Application+Directories
|
||||||
|
|
||||||
|
Most people use the generic ``apps/`` directory with NuttX. That is convenient
|
||||||
|
and well-documented. However, it should always be remembered that NuttX is a
|
||||||
|
stand-alone, general-purpose OS and has **no dependency** on that "canned"
|
||||||
|
application directory.
|
||||||
|
|
||||||
|
This page shows how to create your own, custom application directory from
|
||||||
|
scratch.
|
||||||
|
|
||||||
|
Creating the Custom Application Directory
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
Below is a simple example of the **minimum** custom application directory. It
|
||||||
|
contains only three files: ``Makefile``, ``Kconfig``, and ``hello.c``.
|
||||||
|
|
||||||
|
Makefile
|
||||||
|
--------
|
||||||
|
|
||||||
|
The custom application directory must include a ``Makefile`` that supports all
|
||||||
|
of the make targets expected by the NuttX build system **and** must generate an
|
||||||
|
archive called ``libapps.a`` in the top-level of the custom directory structure.
|
||||||
|
The minimal required targets for the ``Makefile`` look like this:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
APPDIR = ${shell pwd}
|
||||||
|
|
||||||
|
-include $(TOPDIR)/Make.defs
|
||||||
|
|
||||||
|
# files
|
||||||
|
|
||||||
|
CSRCS = hello.c
|
||||||
|
COBJS = hello.o
|
||||||
|
|
||||||
|
ROOTDEPPATH = --dep-path .
|
||||||
|
|
||||||
|
# Build targets
|
||||||
|
|
||||||
|
all: libapps.a
|
||||||
|
.PHONY: dirlinks context preconfig depend clean clean_context distclean
|
||||||
|
.PRECIOUS: libapps$(LIBEXT)
|
||||||
|
|
||||||
|
# Compile C Files
|
||||||
|
|
||||||
|
$(COBJS): %$(OBJEXT): %.c
|
||||||
|
$(call COMPILE, $<, $@)
|
||||||
|
|
||||||
|
# Add object files to the apps archive
|
||||||
|
|
||||||
|
libapps.a: $(COBJS)
|
||||||
|
$(call ARCHIVE, libapps.a, $(COBJS))
|
||||||
|
|
||||||
|
# Create directory links
|
||||||
|
|
||||||
|
dirlinks:
|
||||||
|
|
||||||
|
# Setup any special pre-build context
|
||||||
|
|
||||||
|
context:
|
||||||
|
|
||||||
|
# Setup any special pre-configuration context
|
||||||
|
|
||||||
|
preconfig:
|
||||||
|
|
||||||
|
# Make the dependency file, Make.deps
|
||||||
|
|
||||||
|
depend: Makefile $(CSRCS)
|
||||||
|
$(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
|
||||||
|
|
||||||
|
# Clean the results of the last build
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(call CLEAN)
|
||||||
|
|
||||||
|
# Remove the build context and directory links
|
||||||
|
|
||||||
|
clean_context:
|
||||||
|
|
||||||
|
# Restore the directory to its original state
|
||||||
|
|
||||||
|
distclean: clean clean_context
|
||||||
|
$(call DELFILE, Make.dep)
|
||||||
|
|
||||||
|
# Include dependencies
|
||||||
|
|
||||||
|
-include Make.dep
|
||||||
|
|
||||||
|
|
||||||
|
Kconfig
|
||||||
|
-------
|
||||||
|
|
||||||
|
A ``Kconfig`` file must be included, but it need not contain any meaningful
|
||||||
|
configuration options. This file is where you can add application-specific
|
||||||
|
configuration settings if desired. The minimal ``Kconfig`` might look like:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
# For a description of the syntax of this configuration file,
|
||||||
|
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||||
|
#
|
||||||
|
|
||||||
|
hello.c
|
||||||
|
-------
|
||||||
|
|
||||||
|
Your custom application must compile at least one source file to generate the
|
||||||
|
required ``libapps.a`` archive. One of these source files must include the
|
||||||
|
``main()`` entry point to the application. That main function (or similarly
|
||||||
|
named entry point) is called after OS initialization completes.
|
||||||
|
|
||||||
|
What this application initialization entry point does, how it interacts with
|
||||||
|
the rest of your application, and where the rest of you application code is
|
||||||
|
located is of no concern to the OS. Only this one entry point is needed.
|
||||||
|
|
||||||
|
Below is a small "Hello, World!" example, where ``custom_main()`` is the
|
||||||
|
application entry point:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int custom_main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
printf("Hello, World!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Building with the Custom Application Directory
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
In order to build with the new custom application directory, you need the
|
||||||
|
following in your NuttX configuration:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
CONFIG_APPS_DIR="../custom-apps"
|
||||||
|
CONFIG_USER_ENTRYPOINT="custom_main"
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
You can only access the ``../custom-apps/Kconfig`` file if
|
||||||
|
``CONFIG_APPS_DIR`` is set to ``../custom-apps`` **before** running
|
||||||
|
``make menuconfig``. If you start with an existing configuration, you may
|
||||||
|
face a "chicken-and-egg" situation. One workaround is to manually edit
|
||||||
|
the ``.config`` file before running ``make menuconfig``.
|
||||||
|
|
||||||
|
Alternatively, if you use the ``tools/configure.sh`` script, you can specify the
|
||||||
|
custom-apps directory from the command line:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
tools/configure.sh -a ../custom_apps <board>:<config>
|
||||||
|
|
||||||
|
Afterward, just build NuttX as you normally would. When you run the program that
|
||||||
|
was built with your custom application directory, you should see:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
Hello, World!!
|
84
Documentation/guides/debugging_elf_loadable_modules.rst
Normal file
84
Documentation/guides/debugging_elf_loadable_modules.rst
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
==============================
|
||||||
|
Debugging ELF Loadable Modules
|
||||||
|
==============================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/display/NUTTX/Debugging+ELF+Loadable+Modules
|
||||||
|
|
||||||
|
Debugging ELF modules loaded in memory can be tricky because the load address
|
||||||
|
in memory does not match the addresses in the ELF file. This challenge has long
|
||||||
|
existed for debugging uClinux programs and Linux kernel modules; the same
|
||||||
|
solution can be used with NuttX ELF files (and probably with NxFLAT modules as
|
||||||
|
well). Below is a summary of one way to approach this:
|
||||||
|
|
||||||
|
1. Get ELF Module Load Address
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Put a change in ``nuttx/binfmt`` so that you print the address where the ELF
|
||||||
|
text was loaded into memory.
|
||||||
|
|
||||||
|
Turning on BINFMT debug (``CONFIG_DEBUG_BINFMT=y``) should give you the same
|
||||||
|
information, although it may also provide more output than you really want.
|
||||||
|
|
||||||
|
Alternatively, you could place a ``printf()`` at the beginning of your ``main()``
|
||||||
|
function so that your ELF module can print its own load address. For example,
|
||||||
|
the difference between the address of ``main()`` in your object file and the
|
||||||
|
address of ``main()`` at run time reveals the actual load address.
|
||||||
|
|
||||||
|
2. Make the ELF Module Wait for You
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Insert an infinite loop in the ``main()`` routine of your ELF program. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
volatile bool waitforme;
|
||||||
|
int main (int arc, char **argv)
|
||||||
|
{
|
||||||
|
while (!waitforme);
|
||||||
|
...
|
||||||
|
|
||||||
|
When you start the ELF program, you will see where it was loaded in memory, and
|
||||||
|
the ELF program will remain stuck in the infinite loop. It will continue to
|
||||||
|
wait for ``waitforme`` to become true before proceeding.
|
||||||
|
|
||||||
|
3. Start the Debugger
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Start the debugger, connect to the GDB server, and halt the program. If your
|
||||||
|
debugger is well-behaved, it should stop at the infinite loop in ``main()``.
|
||||||
|
|
||||||
|
4. Load Offset Symbols
|
||||||
|
======================
|
||||||
|
|
||||||
|
Load symbols using the offset where the ELF module was loaded:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
(gdb) add-symbol-file <myprogram> <load-address>
|
||||||
|
|
||||||
|
Here, ``<myprogram>`` is your ELF file containing symbols, and
|
||||||
|
``<load-address>`` is the address where the program text was actually loaded (as
|
||||||
|
determined above). Single-step a couple of times and confirm that you are in the
|
||||||
|
infinite loop.
|
||||||
|
|
||||||
|
5. And Debug
|
||||||
|
============
|
||||||
|
|
||||||
|
Set ``waitforme`` to a non-zero value. Execution should exit the infinite loop,
|
||||||
|
and now you can debug the ELF program loaded into RAM in the usual way.
|
||||||
|
|
||||||
|
An Easier Way?
|
||||||
|
==============
|
||||||
|
|
||||||
|
There might be an alternative that allows you to step into the ELF module
|
||||||
|
without modifying the code to include the ``waitforme`` loop. You could place a
|
||||||
|
breakpoint on the OS function ``task_start()``. That function runs before your
|
||||||
|
ELF program starts, so you should be able to single-step from the OS code
|
||||||
|
directly into your loaded ELF application—no changes to the ELF application
|
||||||
|
required.
|
||||||
|
|
||||||
|
When you step into the application's ``main()``, you have the relocated address
|
||||||
|
of ``main()`` and can use that address (see step #1) to compute the load offset.
|
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
BIN
Documentation/guides/image/custom_app_dir_through_extension.png
Normal file
BIN
Documentation/guides/image/custom_app_dir_through_extension.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
|
@ -59,4 +59,14 @@ Guides
|
||||||
port.rst
|
port.rst
|
||||||
updating_release_system_elf.rst
|
updating_release_system_elf.rst
|
||||||
partially_linked_elf.rst
|
partially_linked_elf.rst
|
||||||
fully_linked_elf.rst
|
fully_linked_elf.rst
|
||||||
|
building_nuttx_with_app_out_of_src_tree.rst
|
||||||
|
building_uclibcpp.rst
|
||||||
|
custom_app_directories.rst
|
||||||
|
debugging_elf_loadable_modules.rst
|
||||||
|
multiple_nsh_sessions.rst
|
||||||
|
nsh_network_link_management.rst
|
||||||
|
ram_rom_disks.rst
|
||||||
|
reading_can_msgs.rst
|
||||||
|
remove_device_drivers_nsh.rst
|
||||||
|
|
||||||
|
|
86
Documentation/guides/multiple_nsh_sessions.rst
Normal file
86
Documentation/guides/multiple_nsh_sessions.rst
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
=====================
|
||||||
|
Multiple NSH Sessions
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/display/NUTTX/Multiple+NSH+Sessions
|
||||||
|
|
||||||
|
Q:
|
||||||
|
I would like to run the NuttShell on multiple serial ports, but haven't
|
||||||
|
figured it out yet; can you point me in the right direction?
|
||||||
|
|
||||||
|
A:
|
||||||
|
Easy. Don't use ``apps/examples/nsh_main.c``. Create your own main function
|
||||||
|
something like this (with all error handling omitted for simplicity). By the
|
||||||
|
way, this is all standard POSIX stuff that you can get detailed information
|
||||||
|
about by just Googling `dup2` or maybe `I/O redirection`:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int my_main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *tty = argv[1];
|
||||||
|
int fd = open(tty, O_RDWR);
|
||||||
|
(void)dup2(fd, 0);
|
||||||
|
(void)dup2(fd, 1);
|
||||||
|
(void)dup2(fd, 2);
|
||||||
|
close(fd);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
And the rest is just like the original ``nsh_main()`` function (in fact,
|
||||||
|
perhaps the existing ``nsh_main()`` function could be optionally extended to
|
||||||
|
accept a console device string?). Then you can start a new NSH session on any
|
||||||
|
TTY like:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
nsh> mynsh /dev/ttyS2 &
|
||||||
|
|
||||||
|
This should cause a new NSH session to appear on ``ttyS2``. That session will
|
||||||
|
persist until you do the following from the new session:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
nsh> exit
|
||||||
|
|
||||||
|
Then the new session, i.e., ``my_main()`` will exit.
|
||||||
|
|
||||||
|
If you were to do something like:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
nsh> mynsh /dev/console
|
||||||
|
|
||||||
|
then you would get nested NSH sessions on the same console. The first session
|
||||||
|
would halt and wait for the second session to take control of the console until
|
||||||
|
it exits. Then the first session will take over console again.
|
||||||
|
|
||||||
|
NuTTY
|
||||||
|
=====
|
||||||
|
|
||||||
|
In a previous discussion, there was talk about implementing the moral equivalent
|
||||||
|
of getty in NuttX (of course, it would be called "nutty"). A simple
|
||||||
|
implementation of nutty would work like this:
|
||||||
|
|
||||||
|
1. It would wait on ``poll()`` on every (configured) serial device.
|
||||||
|
2. Whenever it is awakened, it would start something like ``my_main()`` above
|
||||||
|
on the active serial port.
|
||||||
|
3. NSH has an option to enable logins, but it would be better to remove the
|
||||||
|
existing login information from NSH and centralize it in nutty.
|
||||||
|
|
||||||
|
That way, you could connect to any TTY, hit enter, and you would get an NSH
|
||||||
|
session. Hmm... it is not clear how nutty would get the TTY back after the
|
||||||
|
session is closed. That part may require some additional thought.
|
||||||
|
|
||||||
|
Other Ideas
|
||||||
|
===========
|
||||||
|
|
||||||
|
There are other ways to get multiple NSH sessions:
|
||||||
|
|
||||||
|
- Telnet already supports multiple sessions.
|
||||||
|
- Implement the existing NSH as an ELF program, then you can get multiple NSH
|
||||||
|
sessions with ``posix_spawn`` by simply redirecting I/O.
|
||||||
|
- Using the tiny NxWM window managers, multiple NSH windows are already
|
||||||
|
supported.
|
122
Documentation/guides/nsh_network_link_management.rst
Normal file
122
Documentation/guides/nsh_network_link_management.rst
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
===========================
|
||||||
|
NSH Network Link Management
|
||||||
|
===========================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/display/NUTTX/NSH+Network+Link+Management
|
||||||
|
|
||||||
|
In the past, if the network was not connected when NuttX started, two problems
|
||||||
|
could arise:
|
||||||
|
|
||||||
|
1. It could take a very long time for the NSH prompt to appear because of the
|
||||||
|
sequential initialization (for example, when the network cable is not
|
||||||
|
connected).
|
||||||
|
2. After NuttX came up, installing the network cable would not enable the
|
||||||
|
network; the only way to recover networking was to connect the cable and
|
||||||
|
reset the board.
|
||||||
|
|
||||||
|
Network link management capability has now been added to NSH to address these
|
||||||
|
problems.
|
||||||
|
|
||||||
|
Configuration Options
|
||||||
|
=====================
|
||||||
|
|
||||||
|
A simple feature can be enabled to move network initialization to a separate
|
||||||
|
thread so that it is no longer performed sequentially. With this feature, the
|
||||||
|
network bringup occurs asynchronously, and the NSH prompt appears immediately
|
||||||
|
(although the network may not be available until some time later). That feature
|
||||||
|
is enabled with the following setting and is the first prerequisite for the full
|
||||||
|
NSH link management feature:
|
||||||
|
|
||||||
|
- ``CONFIG_NSH_NETINIT_THREAD``. Refer to the help text in the Kconfig file for
|
||||||
|
this option (``apps/nshlib/Kconfig``). Additional information about this
|
||||||
|
setting is included there.
|
||||||
|
|
||||||
|
The logic that implements NSH network management is provided in
|
||||||
|
``apps/nshlib/nsh_netinit.c``. The behavior of that logic depends on multiple
|
||||||
|
configuration settings. First, there are some additional prerequisites that
|
||||||
|
must be satisfied:
|
||||||
|
|
||||||
|
- ``CONFIG_NETDEV_PHY_IOCTL``
|
||||||
|
Enable PHY IOCTL commands in the Ethernet device driver. Special IOCTL
|
||||||
|
commands must be provided by the Ethernet driver to support certain PHY
|
||||||
|
operations needed for link management. These operations are not complex and
|
||||||
|
are implemented for Atmel SAM4/4, SAMA5 families, and for the STMicro STM32.
|
||||||
|
See ``nuttx/arch/arm/src/sam34/sam_emac.c``,
|
||||||
|
``nuttx/arch/arm/src/sam34/sam_emaca.c``, ``sam_emacb.c``, and ``sam_gmac.c``,
|
||||||
|
and ``nuttx/arch/arm/src/stm32/stm32_eth.c``.
|
||||||
|
- ``CONFIG_ARCH_PHY_INTERRUPT``
|
||||||
|
This is not a user-selectable option. Rather, it is set when selecting a board
|
||||||
|
that supports PHY interrupts. In most architectures, the PHY interrupt is not
|
||||||
|
directly associated with the Ethernet driver. Instead, the PHY interrupt is
|
||||||
|
provided through some board-specific GPIO, and the board-specific logic must
|
||||||
|
provide support for that GPIO interrupt. Specifically, the board logic must:
|
||||||
|
|
||||||
|
1. Provide the function ``arch_phy_irq()`` as described and prototyped in
|
||||||
|
``nuttx/include/nuttx/arch.h``.
|
||||||
|
2. Select ``CONFIG_ARCH_PHY_INTERRUPT`` in the board configuration file to
|
||||||
|
advertise that ``arch_phy_irq()`` is supported.
|
||||||
|
|
||||||
|
Examples can be found at:
|
||||||
|
|
||||||
|
- ``nuttx/boards/arm/sama5/sama5d3x-ek/src/sam_ethernet.c``
|
||||||
|
- ``nuttx/boards/arm/sama5/sama5d3-xplained/src/sam_ethernet.c``
|
||||||
|
- ``nuttx/boards/arm/sama5/sama5d4-ek/src/sam_ethernet.c``
|
||||||
|
- Other requirements: UDP support must be enabled (``CONFIG_NET_UDP``), and
|
||||||
|
signals must not be disabled (``CONFIG_DISABLE_SIGNALS``).
|
||||||
|
|
||||||
|
With all these prerequisites in place, NSH network management can be enabled on
|
||||||
|
the NSH network initialization thread by selecting these additional options:
|
||||||
|
|
||||||
|
- ``CONFIG_NSH_NETINIT_MONITOR``
|
||||||
|
By default, the network initialization thread brings up the network (or
|
||||||
|
fails while trying) then exits, freeing all resources it used. If this option
|
||||||
|
is selected, however, the network initialization thread will persist
|
||||||
|
indefinitely to monitor the network status. Should the network go down (for
|
||||||
|
example, if the cable is removed), the thread will monitor the link status
|
||||||
|
and attempt to bring the network back up. In this scenario, the resources
|
||||||
|
required for network initialization are never released.
|
||||||
|
|
||||||
|
If the network monitor is selected, additional options control its behavior:
|
||||||
|
|
||||||
|
- ``CONFIG_NSH_NETINIT_SIGNO``
|
||||||
|
The network monitor logic receives signals when there is a change in link
|
||||||
|
status. This setting can be used to customize the signal number to avoid
|
||||||
|
conflicts.
|
||||||
|
- ``CONFIG_NSH_NETINIT_RETRYMSEC``
|
||||||
|
When the network is down, the initialization thread will periodically attempt
|
||||||
|
to bring the network back up. Because this can be time-consuming, the retry
|
||||||
|
operation is performed only at the interval specified by this value, in
|
||||||
|
milliseconds.
|
||||||
|
- ``CONFIG_NSH_NETINIT_THREAD_STACKSIZE``
|
||||||
|
The stack size for the network initialization thread.
|
||||||
|
- ``CONFIG_NSH_NETINIT_THREAD_PRIORITY``
|
||||||
|
The network initialization thread priority.
|
||||||
|
|
||||||
|
Overview of the Operation
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Below is a summary of how the NSH management thread operates:
|
||||||
|
|
||||||
|
1. During initialization, the thread opens a UDP socket for IOCTL operations
|
||||||
|
and connects a signal handler.
|
||||||
|
2. It enters a loop. At the beginning of each loop iteration, the thread
|
||||||
|
uses an IOCTL command to register (or re-register) with the Ethernet device
|
||||||
|
to receive a signal whenever the PHY reports a link up or link down
|
||||||
|
interrupt. Re-registration is necessary because the notification disarms
|
||||||
|
after each PHY interrupt.
|
||||||
|
3. The thread reads the link status from both the PHY and the Ethernet device.
|
||||||
|
If they disagree, the network monitor uses an IOCTL command to bring the
|
||||||
|
Ethernet driver up or down to match the current state of the network. If the
|
||||||
|
network is lost, the monitor brings the Ethernet driver down; if the network
|
||||||
|
is regained, the monitor brings the Ethernet driver back up and re-establishes
|
||||||
|
the connection.
|
||||||
|
4. If the PHY and the Ethernet driver agree on the link state, no action is
|
||||||
|
performed.
|
||||||
|
5. At the end of the loop, the network monitor waits for a PHY interrupt or a
|
||||||
|
timeout. When either occurs, control returns to the top of the loop, and the
|
||||||
|
process repeats.
|
||||||
|
6. If a PHY interrupt happens, a signal is delivered to the task and handled by
|
||||||
|
the network monitor’s signal handler, which posts a semaphore to immediately
|
||||||
|
re-awaken the network monitor from its wait.
|
119
Documentation/guides/ram_rom_disks.rst
Normal file
119
Documentation/guides/ram_rom_disks.rst
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
=======================
|
||||||
|
RAM Disks and ROM Disks
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/display/NUTTX/RAM+Disks+and+ROM+Disks
|
||||||
|
|
||||||
|
NSH mkrd Command
|
||||||
|
================
|
||||||
|
|
||||||
|
The typical way to create a RAM disk is by using the NuttShell (NSH) ``mkrd``
|
||||||
|
command. The syntax is:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
mkrd [-m <minor>] [-s <sector-size>] <nsectors>
|
||||||
|
|
||||||
|
This command creates a RAM disk consisting of ``<nsectors>`` sectors, each of
|
||||||
|
size ``<sector-size>`` (or 512 bytes if ``<sector-size>`` is not specified). The
|
||||||
|
RAM disk is then registered as ``/dev/ram<minor>``. If ``<minor>`` is not
|
||||||
|
specified, ``mkrd`` attempts to register the RAM disk as ``/dev/ram0``.
|
||||||
|
|
||||||
|
Internally, the NSH ``mkrd`` command is a simple wrapper around the OS
|
||||||
|
``boardctl()`` interface, using the ``BOARDIOC_MKRD`` command. “Under the hood,”
|
||||||
|
this ``boardctl()`` command performs the following:
|
||||||
|
|
||||||
|
1. Allocates kernel-space memory with ``kmm_malloc()`` of size ``<nsectors>``
|
||||||
|
times ``<sector-size>``
|
||||||
|
2. Zeros the allocated memory, and
|
||||||
|
3. Calls the OS-internal function ``ramdisk_register()`` to create the RAM disk.
|
||||||
|
|
||||||
|
NSH ROMFS /etc Support
|
||||||
|
======================
|
||||||
|
|
||||||
|
A ROM disk is a block device created from a read-only file system image stored
|
||||||
|
in FLASH or other ROM. There is no NSH command available to create a ROM disk
|
||||||
|
at runtime. However, it is possible to enable ROM disk support in NSH using the
|
||||||
|
``CONFIG_NSH_ROMFSETC`` option, as described in the section on NSH start-up
|
||||||
|
scripts in the `NSH User Guide <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=139629410>`_.
|
||||||
|
|
||||||
|
Any application is able to create a ROM disk using the ``boardctl()`` interface
|
||||||
|
with the ``BOARDIOC_ROMDISK`` command.
|
||||||
|
|
||||||
|
Creating RAM Disks in Board Bring-Up Logic
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
RAM disks may be created in board-specific initialization logic that runs in
|
||||||
|
supervisor mode. That logic might look as follows:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int board_ramdisk(int minor, unsigned int sectsize, unsigned int nsectors)
|
||||||
|
{
|
||||||
|
size_t allocsize = (size_t)sectsize * (size_t)nsectors;
|
||||||
|
FAR uint8_t *buffer;
|
||||||
|
|
||||||
|
/* Allocate the memory backing up the ramdisk */
|
||||||
|
|
||||||
|
buffer = (FAR uint8_t *)kmm_zalloc(allocsize);
|
||||||
|
if (buffer == NULL)
|
||||||
|
{
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then register the ramdisk */
|
||||||
|
|
||||||
|
ret = ramdisk_register(minor, buffer, nsectors, sectsize,
|
||||||
|
RDFLAG_WRENABLED | RDFLAG_FUNLINK);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
kmm_free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Alternatively, this could be replaced by a call to the OS internal function
|
||||||
|
``mkrd()``.
|
||||||
|
|
||||||
|
Creating ROM Disks in Board Bring-Up Logic
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Currently, the ``romdisk_register()`` function is only available within the
|
||||||
|
OS. Certain logic in ``apps/`` directly calls ``romdisk_register()``, which
|
||||||
|
violates the portable POSIX OS interface. The correct approach for an
|
||||||
|
application is to create a ROM disk via ``boardctl(BOARDIOC_ROMDISK)`` as
|
||||||
|
described above. Calling ``romdisk_register()`` directly is not only a
|
||||||
|
violation of the NuttX portable interface, but also is not allowed in
|
||||||
|
PROTECTED or KERNEL build modes.
|
||||||
|
|
||||||
|
ROM disks, i.e., read-only disks in FLASH, can be created by board bring-up
|
||||||
|
logic in a way similar to RAM disks, with the following caveats:
|
||||||
|
|
||||||
|
- The FLASH region is not allocated; the FLASH address, the sector size, and the
|
||||||
|
number of sectors must already be known.
|
||||||
|
- The ``romdisk_register()`` function is used instead of ``ramdisk_register()``.
|
||||||
|
|
||||||
|
A simple example could look like:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int board_romdisk(int minor, FAR uint8_t *buffer, unsigned int sectsize,
|
||||||
|
unsigned int nsectors)
|
||||||
|
{
|
||||||
|
/* Register the romdisk */
|
||||||
|
|
||||||
|
return romdisk_register(minor, buffer, nsectors, sectsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
Calling ``romdisk_register()`` is equivalent to calling ``ramdisk_register()``
|
||||||
|
with the final parameter ``flags == 0``.
|
||||||
|
|
||||||
|
Most ROM disks use the ROMFS file system, although CROMFS is another option.
|
||||||
|
Creating ROMFS file system images involves several steps. Tools are available
|
||||||
|
to simplify the process of building ROMFS images, but that topic is outside the
|
||||||
|
scope of this Wiki page.
|
62
Documentation/guides/reading_can_msgs.rst
Normal file
62
Documentation/guides/reading_can_msgs.rst
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
====================
|
||||||
|
Reading CAN Messages
|
||||||
|
====================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/display/NUTTX/Reading+CAN+Messages
|
||||||
|
|
||||||
|
Twice now, there have been complaints or issues about reading messages from the
|
||||||
|
CAN driver. The usual concern is that the driver is somehow losing or dropping
|
||||||
|
CAN messages. In these cases, it is often discovered that the CAN driver is
|
||||||
|
being used incorrectly and, as is human nature, the driver itself is blamed for
|
||||||
|
the problem.
|
||||||
|
|
||||||
|
When reading from the CAN driver, multiple messages may be returned, depending
|
||||||
|
on two factors:
|
||||||
|
|
||||||
|
1. The size of the returned CAN messages.
|
||||||
|
2. The size of the buffer provided to receive CAN messages.
|
||||||
|
|
||||||
|
It should never be assumed that a single message will be returned; making this
|
||||||
|
assumption can lead to lost CAN messages under conditions in which the read
|
||||||
|
buffer can hold more than one small message. The following example shows how to
|
||||||
|
properly handle the CAN read operation:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#define BUFLEN 128 /* Some arbitrary size for the CAN RX buffer */
|
||||||
|
|
||||||
|
FAR struct can_msg_s *msg;
|
||||||
|
char rxbuffer[BUFLEN];
|
||||||
|
ssize_t nread;
|
||||||
|
int nbytes;
|
||||||
|
int msglen
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Read messages into the RX buffer */
|
||||||
|
|
||||||
|
nread = read(fd, rxbuffer, BUFLEN);
|
||||||
|
|
||||||
|
/* Check for read errors */
|
||||||
|
...
|
||||||
|
|
||||||
|
/* Process each message in the RX buffer */
|
||||||
|
|
||||||
|
for (i = 0; i <= nread - CAN_MSGLEN(0); i += msglen)
|
||||||
|
{
|
||||||
|
/* Get the next message from the RX buffer */
|
||||||
|
|
||||||
|
msg = (FAR struct can_msg_s *)&rxbuffer[i];
|
||||||
|
nbytes = can_dlc2bytes(msg->cm_hdr.ch_dlc);
|
||||||
|
msglen = CAN_MSGLEN(nbytes);
|
||||||
|
|
||||||
|
DEBUGASSERT(i + msglen < BUFLEN);
|
||||||
|
|
||||||
|
/* Process the next CAN message */
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
By looping over the read buffer and parsing out each CAN message, it is
|
||||||
|
possible to avoid losing messages that are stored contiguously in the input
|
||||||
|
buffer.
|
101
Documentation/guides/remove_device_drivers_nsh.rst
Normal file
101
Documentation/guides/remove_device_drivers_nsh.rst
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
================================
|
||||||
|
Removing Device Drivers with NSH
|
||||||
|
================================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/display/NUTTX/Removing+Device+Drivers+with+NSH
|
||||||
|
|
||||||
|
NuttX and Unix-like Operating Systems Compared
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
There are many things that are called device drivers. In this context, the
|
||||||
|
discussion is limited to **character device drivers**. In NuttX, character
|
||||||
|
device drivers are represented by device driver nodes in the top-level :doc:`pseudo
|
||||||
|
filesystem </components/filesystem/pseudofs>`.
|
||||||
|
|
||||||
|
Standard Unix-like operating systems also support device driver nodes, which
|
||||||
|
superficially resemble NuttX device driver nodes: Both look like files and
|
||||||
|
usually reside under the top-level ``/dev`` directory. Both can be accessed
|
||||||
|
with standard POSIX file system commands such as ``open()``, ``close()``,
|
||||||
|
``read()``, ``write()``, and so forth. However, the similarity ends there.
|
||||||
|
|
||||||
|
The payload of a standard Unix-like operating system device driver node is a
|
||||||
|
device major and minor number. These major and minor device numbers are used to
|
||||||
|
look up the actual device driver interface using internal OS logic and data
|
||||||
|
structures. A NuttX device node, by contrast, directly holds the device driver
|
||||||
|
interface with no intervening lookup. This design is less flexible, but it is
|
||||||
|
more efficient and conserves limited resources in an embedded system.
|
||||||
|
|
||||||
|
In standard Unix-like operating systems, the device node can simply be deleted
|
||||||
|
using the shell command ``rm`` or the programmatic interface ``unlink()``. The
|
||||||
|
node is removed, and nothing special happens to the underlying device driver
|
||||||
|
(except that it may no longer be accessible).
|
||||||
|
|
||||||
|
In NuttX, if the device node were removed in the same way, the entire device
|
||||||
|
interface would also be removed, effectively breaking the driver. Internally,
|
||||||
|
NuttX supports a function called ``unregister_driver()`` that can be invoked
|
||||||
|
to remove a device driver. Therefore, removing the device driver node must
|
||||||
|
behave as though ``unregister_driver()`` were called.
|
||||||
|
|
||||||
|
The unlink() Method
|
||||||
|
===================
|
||||||
|
|
||||||
|
How is this accomplished in NuttX? It is done via a special device driver
|
||||||
|
method called ``unlink()``.
|
||||||
|
|
||||||
|
NuttX device drivers are implemented via a vtable of function pointers. That
|
||||||
|
vtable defines the interface between the pseudo-file system and the device
|
||||||
|
driver. This vtable is the structure ``struct file_operations`` defined in
|
||||||
|
``[nuttx]/include/nuttx/fs/fs.h``. It provides several interfaces that closely
|
||||||
|
match the standard POSIX interfaces—``open()``, ``close()``, ``read()``,
|
||||||
|
``write()``, etc.—and also includes a method called ``unlink()``. This
|
||||||
|
``unlink()`` method is called by the NuttX VFS when a user removes a device
|
||||||
|
driver node.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Removal of device driver nodes is only permitted if
|
||||||
|
``CONFIG_DISABLE_PSEUDOFS_OPERATIONS`` is **not** defined. All pseudo-file
|
||||||
|
system operations may be suppressed to reduce the FLASH footprint in systems
|
||||||
|
with extremely limited resources.
|
||||||
|
|
||||||
|
Removing a Device Node from NSH
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Below is a summary of what happens when a device node is deleted using the NSH
|
||||||
|
``rm`` command:
|
||||||
|
|
||||||
|
1. The user enters the ``rm`` command. The NSH parser recognizes the command
|
||||||
|
and transfers control to the NSH function ``cmd_rm()``.
|
||||||
|
|
||||||
|
2. ``cmd_rm()`` verifies the command, then calls the standard POSIX
|
||||||
|
``unlink()`` interface. The logic in the VFS ``unlink()`` function in
|
||||||
|
``[nuttx]/fs/vfs/fs_unlink.c`` is then executed.
|
||||||
|
|
||||||
|
3. The VFS ``unlink()`` detects that the target to be removed is a device node
|
||||||
|
in the top-level pseudo-file system. It calls the device driver's
|
||||||
|
``unlink()`` method. It also removes the device node from the
|
||||||
|
pseudo-filesystem. However, the underlying resources required to support
|
||||||
|
the device driver interface may remain until the device driver frees those
|
||||||
|
resources.
|
||||||
|
|
||||||
|
4. When the device driver's ``unlink()`` method is called, it determines if
|
||||||
|
the device resources can be freed immediately. If so, it frees those
|
||||||
|
resources. If, for example, there are still open references to the device
|
||||||
|
driver, it may defer freeing the resources until the last client has closed
|
||||||
|
the device driver and there are no open references. In such a case, it may
|
||||||
|
set a flag indicating that the device driver has been unlinked.
|
||||||
|
|
||||||
|
5. If freeing of device driver resources has been deferred, that flag will be
|
||||||
|
examined later. For instance, when the last client of the device driver
|
||||||
|
closes its reference to the driver, it checks whether the unlink operation
|
||||||
|
was deferred. If so, it frees any remaining device driver resources at that
|
||||||
|
time.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Some character device driver instances do not implement the ``unlink()``
|
||||||
|
method. If problems arise when attempting to remove character drivers as
|
||||||
|
described in this Wiki page, a missing ``unlink()`` method is the most
|
||||||
|
likely cause.
|
|
@ -2,6 +2,10 @@
|
||||||
Updating a Release System with ELF Programs
|
Updating a Release System with ELF Programs
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Migrated from:
|
||||||
|
https://cwiki.apache.org/confluence/display/NUTTX/Updating+a+Release+System+with+ELF+Programs
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
Migrated from:
|
Migrated from:
|
||||||
https://cwiki.apache.org/confluence/display/NUTTX/Updating+a+Release+System+with+ELF+Programs
|
https://cwiki.apache.org/confluence/display/NUTTX/Updating+a+Release+System+with+ELF+Programs
|
||||||
|
|
Loading…
Reference in a new issue