Compare commits
No commits in common. "master" and "master-31012017" have entirely different histories.
master
...
master-310
7
.gitmodules
vendored
7
.gitmodules
vendored
|
@ -4,15 +4,16 @@
|
|||
[submodule "tools/cc2538-bsl"]
|
||||
path = tools/cc2538-bsl
|
||||
url = https://github.com/JelmerT/cc2538-bsl.git
|
||||
[submodule "cpu/cc26xx-cc13xx/lib/cc26xxware"]
|
||||
path = cpu/cc26xx-cc13xx/lib/cc26xxware
|
||||
url = https://github.com/contiki-os/cc26xxware.git
|
||||
[submodule "cpu/cc26xx-cc13xx/lib/cc13xxware"]
|
||||
path = cpu/cc26xx-cc13xx/lib/cc13xxware
|
||||
url = https://github.com/contiki-os/cc13xxware.git
|
||||
[submodule "platform/stm32nucleo-spirit1/stm32cube-lib"]
|
||||
path = platform/stm32nucleo-spirit1/stm32cube-lib
|
||||
url = https://github.com/STclab/stm32nucleo-spirit1-lib
|
||||
|
||||
[submodule "tools/sensniff"]
|
||||
path = tools/sensniff
|
||||
url = https://github.com/g-oikonomou/sensniff.git
|
||||
[submodule "apps/tinydtls"]
|
||||
path = apps/tinydtls
|
||||
url = https://github.com/iot-lab/armour-tinydtls.git
|
||||
|
|
|
@ -14,7 +14,7 @@ before_script:
|
|||
|
||||
## Install doxygen
|
||||
- if [ ${BUILD_CATEGORY:-0} = doxygen ] ; then
|
||||
sudo add-apt-repository ppa:libreoffice/ppa -y && sudo apt-get -qq update &&
|
||||
sudo add-apt-repository ppa:libreoffice/libreoffice-4-4 -y && sudo apt-get -qq update &&
|
||||
sudo apt-get --no-install-suggests --no-install-recommends -qq install doxygen &&
|
||||
doxygen --version ;
|
||||
fi
|
||||
|
@ -85,7 +85,7 @@ before_script:
|
|||
- if [ ${BUILD_ARCH:-0} = jn516x ] ; then
|
||||
$WGET http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 &&
|
||||
$WGET http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part2.tar.bz2 &&
|
||||
$WGET http://simonduq.github.io/resources/jn516x-sdk-4163-1416.tar.bz2 &&
|
||||
$WGET http://simonduq.github.io/resources/jn516x-sdk-4163.tar.bz2 &&
|
||||
mkdir /tmp/jn516x-sdk /tmp/ba-elf-gcc &&
|
||||
tar xjf jn516x-sdk-*.tar.bz2 -C /tmp/jn516x-sdk &&
|
||||
tar xjf ba-elf-gcc-*part1.tar.bz2 -C /tmp/ba-elf-gcc &&
|
||||
|
@ -163,4 +163,3 @@ env:
|
|||
- BUILD_TYPE='llsec' MAKE_TARGETS='cooja'
|
||||
- BUILD_TYPE='compile-avr' BUILD_CATEGORY='compile' BUILD_ARCH='avr-rss2'
|
||||
- BUILD_TYPE='ieee802154'
|
||||
- BUILD_TYPE='tsch'
|
||||
|
|
494
LICENSE
494
LICENSE
|
@ -1,37 +1,3 @@
|
|||
A note on Licensing (2017-03-17):
|
||||
Github has recently (2017-03-01) changed their license terms:
|
||||
https://help.github.com/articles/github-terms-of-service/
|
||||
There were comments that this may violate some GPL and creative commons
|
||||
licenses:
|
||||
http://joeyh.name/blog/entry/removing_everything_from_github/
|
||||
https://www.mirbsd.org/permalinks/wlog-10_e20170301-tg.htm
|
||||
But also voices that don't see a problem:
|
||||
https://www.earth.li/~noodles/blog/2017/03/github-tos-change.html
|
||||
If your're german-speaking you may also want to read the two Heise
|
||||
articles:
|
||||
https://www.heise.de/developer/meldung/GitHub-eckt-mit-neuen-Nutzungsbedingungen-an-3647980.html
|
||||
https://www.heise.de/developer/meldung/FSF-aeussert-sich-zu-den-GitHub-Nutzungsbedingungen-3657040.html
|
||||
|
||||
We trust that the problematic part in section D.5:
|
||||
"If you set your pages and repositories to be viewed publicly, you grant
|
||||
each User of GitHub a nonexclusive, worldwide license to access your
|
||||
Content through the GitHub Service, and to use, display and perform your
|
||||
Content, and to reproduce your Content solely on GitHub as permitted
|
||||
through GitHub's functionality." that the part "solely on GitHub as
|
||||
permitted through GitHub's functionality" also applies to "display and
|
||||
perform your Content". If the latter part of the sentence would stand
|
||||
alone it could be interpreted that we would grant *everybody*
|
||||
essentially an unlimited license (which we cannot because the authors
|
||||
from whom we forked applied other licenses). This interpretation is
|
||||
further supported by the fact that Github writes "You may grant further
|
||||
rights if you adopt a license." that in fact the statements above only
|
||||
apply to the rendering on Github.
|
||||
|
||||
Note that in the following we have two licenses, the 3-clause BSD and
|
||||
the LGPL license in short:
|
||||
- Contiki OS (and our modification to it) are 3-clause BSD
|
||||
- Our Arduino compatibility Layer on top of Contiki OS is LGPL
|
||||
|
||||
Contiki is licensed under the 3-clause BSD license. This license gives
|
||||
everyone the right to use and distribute the code, either in binary or
|
||||
source code format, as long as the copyright license is retained in
|
||||
|
@ -70,463 +36,3 @@ of license. The license text is:
|
|||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Arduino-compatibility layer if not otherwise noted is under the
|
||||
following license:
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ CONTIKI_SOURCEFILES += $(CONTIKIFILES)
|
|||
CONTIKIDIRS += ${addprefix $(CONTIKI)/core/,dev lib net net/llsec net/mac net/rime \
|
||||
net/rpl sys cfs ctk lib/ctk loader . }
|
||||
|
||||
oname = ${patsubst %.cpp,%.o,${patsubst %.c,%.o,${patsubst %.S,%.o,$(1)}}}
|
||||
oname = ${patsubst %.c,%.o,${patsubst %.S,%.o,$(1)}}
|
||||
|
||||
CONTIKI_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CONTIKI_SOURCEFILES)}}
|
||||
|
||||
|
@ -157,14 +157,12 @@ endif
|
|||
|
||||
ifeq ($(V),1)
|
||||
TRACE_CC =
|
||||
TRACE_CXX =
|
||||
TRACE_LD =
|
||||
TRACE_AR =
|
||||
TRACE_AS =
|
||||
Q=
|
||||
else
|
||||
TRACE_CC = @echo " CC " $<
|
||||
TRACE_CXX = @echo " CXX " $<
|
||||
TRACE_LD = @echo " LD " $@
|
||||
TRACE_AR = @echo " AR " $@
|
||||
TRACE_AS = @echo " AS " $<
|
||||
|
@ -187,7 +185,6 @@ SOURCEDIRS = . $(PROJECTDIRS) $(CONTIKI_TARGET_DIRS_CONCAT) \
|
|||
$(CONTIKI_CPU_DIRS_CONCAT) $(CONTIKIDIRS) $(APPDS) $(EXTERNALDIRS) ${dir $(target_makefile)}
|
||||
|
||||
vpath %.c $(SOURCEDIRS)
|
||||
vpath %.cpp $(SOURCEDIRS)
|
||||
vpath %.S $(SOURCEDIRS)
|
||||
|
||||
CFLAGS += ${addprefix -I,$(SOURCEDIRS) $(CONTIKI)}
|
||||
|
@ -206,7 +203,7 @@ endif
|
|||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include ${addprefix $(OBJECTDIR)/,$(CONTIKI_SOURCEFILES:.c=.d) \
|
||||
$(PROJECT_OBJECTFILES:.o=.d)}
|
||||
$(PROJECT_SOURCEFILES:.c=.d)}
|
||||
endif
|
||||
|
||||
### See http://make.paulandlesley.org/autodep.html#advanced
|
||||
|
@ -245,13 +242,6 @@ $(OBJECTDIR)/%.o: %.c | $(OBJECTDIR)
|
|||
@$(FINALIZE_DEPENDENCY)
|
||||
endif
|
||||
|
||||
ifndef CUSTOM_RULE_CPP_TO_OBJECTDIR_O
|
||||
$(OBJECTDIR)/%.o: %.cpp | $(OBJECTDIR)
|
||||
$(TRACE_CXX)
|
||||
$(Q)$(CXX) $(CFLAGS) -MMD -c $< -o $@
|
||||
@$(FINALIZE_DEPENDENCY)
|
||||
endif
|
||||
|
||||
ifndef CUSTOM_RULE_S_TO_OBJECTDIR_O
|
||||
$(OBJECTDIR)/%.o: %.S | $(OBJECTDIR)
|
||||
$(TRACE_AS)
|
||||
|
@ -264,12 +254,6 @@ ifndef CUSTOM_RULE_C_TO_O
|
|||
$(Q)$(CC) $(CFLAGS) -c $< -o $@
|
||||
endif
|
||||
|
||||
ifndef CUSTOM_RULE_CPP_TO_O
|
||||
%.o: %.cpp
|
||||
$(TRACE_CXX)
|
||||
$(Q)$(CXX) $(CFLAGS) -c $< -o $@
|
||||
endif
|
||||
|
||||
|
||||
ifndef CUSTOM_RULE_C_TO_CO
|
||||
%.co: %.c
|
||||
|
@ -304,25 +288,6 @@ endif
|
|||
%.flashprof: %.$(TARGET)
|
||||
$(NM) -S -td --size-sort $< | grep -i " [t] " | cut -d' ' -f2,4
|
||||
|
||||
viewconf:
|
||||
@echo "----------------- Make variables: --------------"
|
||||
@echo "##### \"TARGET\": ________________________________ $(TARGET)"
|
||||
@echo "##### \"BOARD\": _________________________________ $(BOARD)"
|
||||
@echo "##### \"MAKE_MAC\": ______________________________ $(MAKE_MAC)"
|
||||
@echo "##### \"MAKE_NET\": ______________________________ $(MAKE_NET)"
|
||||
@echo "##### \"MAKE_ROUTING\": __________________________ $(MAKE_ROUTING)"
|
||||
ifdef MAKE_COAP_DTLS_KEYSTORE
|
||||
@echo "##### \"MAKE_COAP_DTLS_KEYSTORE\": _______________ $(MAKE_COAP_DTLS_KEYSTORE)"
|
||||
endif
|
||||
@echo "----------------- C variables: -----------------"
|
||||
$(Q)$(CC) $(CFLAGS) -E $(CONTIKI)/tools/viewconf.c | grep \#\#\#\#\#
|
||||
@echo "------------------------------------------------"
|
||||
@echo "'==' Means the flag is set to a given a value"
|
||||
@echo "'->' Means the flag is unset, but will default to a given value"
|
||||
@echo "'><' Means the flag is unset and has no default value"
|
||||
@echo "To view more Make variables, edit $(CONTIKI)/Makefile.include, rule 'viewconf'"
|
||||
@echo "To view more C variables, edit $(CONTIKI)/tools/viewconf.c"
|
||||
|
||||
# Don't treat %.$(TARGET) as an intermediate file because it is
|
||||
# in fact the primary target.
|
||||
.PRECIOUS: %.$(TARGET)
|
||||
|
@ -332,8 +297,6 @@ endif
|
|||
# the match-anything rule below instead.
|
||||
%: %.c
|
||||
|
||||
%: %.cpp
|
||||
|
||||
# Match-anything pattern rule to allow the project makefiles to
|
||||
# abstract from the actual binary name. It needs to contain some
|
||||
# command in order to be a rule, not just a prerequisite.
|
||||
|
|
11
README.md
11
README.md
|
@ -1,6 +1,8 @@
|
|||
The Contiki Operating System
|
||||
============================
|
||||
|
||||
[![Build Status](https://travis-ci.org/contiki-os/contiki.svg?branch=master)](https://travis-ci.org/contiki-os/contiki/branches)
|
||||
|
||||
Contiki is an open source operating system that runs on tiny low-power
|
||||
microcontrollers and makes it possible to develop applications that
|
||||
make efficient use of the hardware while providing standardized
|
||||
|
@ -15,12 +17,3 @@ and so on.
|
|||
For more information, see the Contiki website:
|
||||
|
||||
[http://contiki-os.org](http://contiki-os.org)
|
||||
|
||||
This fork of the Contiki Operating System adds support for our Merkur
|
||||
Board, adds a lot of examples (with different hardware) and puts an
|
||||
Arduino compatibility layer on top of Contiki-OS that allows Arduino
|
||||
Sketches -- and a lot of drivers for Arduino compatible hardware -- to
|
||||
run under Contiki-OS.
|
||||
|
||||
For the licensing terms (also in the light of recent debates of Github
|
||||
changed Terms of Service on 2017-03-01) see the file LICENSE.
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
arduino_src = arduino-process.c
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
%.cpp: %.pde
|
||||
echo '#include "Arduino.h"' > $@
|
||||
echo '#include "$<"' >> $@
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
Arduino Compatibility
|
||||
=====================
|
||||
|
||||
This application contains hardware-independent implementations of
|
||||
arduino compatibilty libraries and include files to be used with
|
||||
contiki.
|
||||
|
||||
The whole arduino compatibility library is work in progress. Note that
|
||||
features having to do with timers like `millis` and `delay` are
|
||||
currently untested. In Arduino they use timer 0 of the AVR
|
||||
microcontroller. It should be investigated to use the hardware timer
|
||||
already in use by contiki (on the OSD-merkur platform this is currently
|
||||
timer 5).
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Ralf Schlatterbeck Open Source Consulting
|
||||
* 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addgroup Arduino Process
|
||||
*
|
||||
* This wraps the Arduino-API entry points `loop` and `setup` in a
|
||||
* contiki process.
|
||||
*
|
||||
* If the normal contiki includes are used and resources initialized in
|
||||
* `setup`, Contiki resources can be used in an arduino sketch.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Wrapper for Arduino sketches
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "arduino-process.h"
|
||||
#include "hw_timer.h"
|
||||
#include "adc.h"
|
||||
#include "hw-arduino.h"
|
||||
#include "contiki.h"
|
||||
#include "project-conf.h"
|
||||
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
|
||||
#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5])
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#define PRINT6ADDR(addr)
|
||||
#define PRINTLLADDR(addr)
|
||||
#endif
|
||||
|
||||
|
||||
extern volatile uint8_t mcusleepcycle;
|
||||
#if PLATFORM_HAS_BUTTON
|
||||
#include "rest-engine.h"
|
||||
#include "dev/button-sensor.h"
|
||||
extern resource_t res_event, res_separate;
|
||||
#endif /* PLATFORM_HAS_BUTTON */
|
||||
|
||||
volatile uint8_t mcusleepcycleval;
|
||||
/* 0 dont sleep; 1 sleep */
|
||||
uint8_t mcusleep;
|
||||
|
||||
/*-------------- enabled sleep mode ----------------------------------------*/
|
||||
void
|
||||
mcu_sleep_init(void)
|
||||
{
|
||||
mcusleepcycleval=mcusleepcycle;
|
||||
mcu_sleep_disable(); // if a shell is active we can type
|
||||
}
|
||||
void
|
||||
mcu_sleep_disable(void)
|
||||
{
|
||||
mcusleep=2;
|
||||
mcu_sleep_off();
|
||||
}
|
||||
void
|
||||
mcu_sleep_enable(void)
|
||||
{
|
||||
mcusleep=0;
|
||||
}
|
||||
void
|
||||
mcu_sleep_on(void)
|
||||
{
|
||||
if(mcusleep == 0){
|
||||
mcusleepcycle= mcusleepcycleval;
|
||||
}
|
||||
}
|
||||
/*--------------- disable sleep mode ---------------------------------------*/
|
||||
void
|
||||
mcu_sleep_off(void)
|
||||
{
|
||||
mcusleepcycle=0;
|
||||
}
|
||||
/*---------------- set duty cycle value ------------------------------------*/
|
||||
void
|
||||
mcu_sleep_set(uint8_t value)
|
||||
{
|
||||
mcusleepcycleval= value;
|
||||
// mcusleepcycle = mcusleepcycleval;
|
||||
}
|
||||
|
||||
PROCESS(arduino_sketch, "Arduino Sketch Wrapper");
|
||||
|
||||
#ifndef LOOP_INTERVAL
|
||||
#define LOOP_INTERVAL (1 * CLOCK_SECOND)
|
||||
#endif
|
||||
#define START_MCUSLEEP (10 * CLOCK_SECOND)
|
||||
|
||||
PROCESS_THREAD(arduino_sketch, ev, data)
|
||||
{
|
||||
static struct etimer loop_periodic_timer;
|
||||
static struct etimer start_mcusleep_timer;
|
||||
|
||||
PROCESS_BEGIN();
|
||||
adc_init ();
|
||||
mcu_sleep_init ();
|
||||
setup ();
|
||||
/* Define application-specific events here. */
|
||||
etimer_set(&loop_periodic_timer, LOOP_INTERVAL);
|
||||
etimer_set(&start_mcusleep_timer, START_MCUSLEEP);
|
||||
|
||||
while (1) {
|
||||
PROCESS_WAIT_EVENT();
|
||||
#if PLATFORM_HAS_BUTTON
|
||||
if(ev == sensors_event && data == &button_sensor) {
|
||||
mcu_sleep_off();
|
||||
PRINTF("*******BUTTON*******\n");
|
||||
button ();
|
||||
mcu_sleep_on();
|
||||
}
|
||||
#endif /* PLATFORM_HAS_BUTTON */
|
||||
if(etimer_expired(&start_mcusleep_timer)) {
|
||||
PRINTF("mcusleep_timer %d\n",mcusleep);
|
||||
if(mcusleep == 1){
|
||||
PRINTF("mcu sleep on\n");
|
||||
mcu_sleep_enable();
|
||||
mcu_sleep_on();
|
||||
}
|
||||
if (mcusleep > 0) {
|
||||
mcusleep--;
|
||||
}
|
||||
etimer_reset(&start_mcusleep_timer);
|
||||
}
|
||||
|
||||
if(etimer_expired(&loop_periodic_timer)) {
|
||||
mcu_sleep_off();
|
||||
loop ();
|
||||
mcu_sleep_on();
|
||||
etimer_reset(&loop_periodic_timer);
|
||||
}
|
||||
}
|
||||
PROCESS_END();
|
||||
}
|
||||
|
||||
/*
|
||||
* VI settings, see coding style
|
||||
* ex:ts=8:et:sw=2
|
||||
*/
|
||||
|
||||
/** @} */
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Ralf Schlatterbeck Open Source Consulting
|
||||
* 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \devgroup Arduino Process
|
||||
*
|
||||
* This wraps the Arduino-API entry points `loop` and `setup` in a
|
||||
* contiki process.
|
||||
*
|
||||
* If the normal contiki includes are used and resources initialized in
|
||||
* `setup`, Contiki resources can be used in an arduino sketch.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Wrapper for Arduino sketches
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
|
||||
/*--------------- enable sleep mode ---------------------------------------*/
|
||||
void mcu_sleep_enable(void);
|
||||
/*--------------- disable sleep mode ---------------------------------------*/
|
||||
void mcu_sleep_disable(void);
|
||||
/*--------------- sleep mode on---------------------------------------*/
|
||||
void mcu_sleep_on(void);
|
||||
/*--------------- sleep mode off---------------------------------------*/
|
||||
void mcu_sleep_off(void);
|
||||
/*---------------- set sleep value ------------------------------------*/
|
||||
void mcu_sleep_set(uint8_t value);
|
||||
|
||||
extern void loop (void);
|
||||
extern void setup (void);
|
||||
extern void arduino_init (void);
|
||||
extern void button (void);
|
||||
|
||||
extern struct process arduino_sketch;
|
||||
|
||||
/*
|
||||
* VI settings, see coding style
|
||||
* ex:ts=8:et:sw=2
|
||||
*/
|
||||
|
||||
/** @} */
|
|
@ -4,18 +4,3 @@ er-coap_src = er-coap.c er-coap-engine.c er-coap-transactions.c \
|
|||
|
||||
# Erbium will implement the REST Engine
|
||||
CFLAGS += -DREST=coap_rest_implementation
|
||||
|
||||
ifeq ($(WITH_DTLS_COAP),1)
|
||||
er-coap_src += er-coap-dtls.c
|
||||
|
||||
# Load tinydtls
|
||||
APPS += tinydtls
|
||||
$(CONTIKI)/apps/tinydtls/Makefile.tinydtls:
|
||||
@echo " You should run 'git submodule update --init' to clone 'app/tinydtls'"
|
||||
@exit 1
|
||||
include $(CONTIKI)/apps/tinydtls/Makefile.tinydtls
|
||||
PROJECTDIRS+=$(CONTIKI)/apps/tinydtls/aes $(CONTIKI)/apps/tinydtls/sha2 $(CONTIKI)/apps/tinydtls/ecc
|
||||
|
||||
else
|
||||
er-coap_src += er-coap-udp.c
|
||||
endif
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef _ER_COAP_COMMUNICATION_H_
|
||||
#define _ER_COAP_COMMUNICATION_H_
|
||||
|
||||
#include "contiki.h"
|
||||
|
||||
void
|
||||
coap_init_communication_layer(uint16_t port);
|
||||
|
||||
void
|
||||
coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length);
|
||||
|
||||
void
|
||||
coap_handle_receive(void);
|
||||
|
||||
#endif
|
|
@ -94,7 +94,6 @@ typedef enum {
|
|||
NOT_FOUND_4_04 = 132, /* NOT_FOUND */
|
||||
METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */
|
||||
NOT_ACCEPTABLE_4_06 = 134, /* NOT_ACCEPTABLE */
|
||||
REQUEST_ENTITY_INCOMPLETE_4_08 = 136, /* REQUEST_ENTITY_INCOMPLETE */
|
||||
PRECONDITION_FAILED_4_12 = 140, /* BAD_REQUEST */
|
||||
REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */
|
||||
UNSUPPORTED_MEDIA_TYPE_4_15 = 143, /* UNSUPPORTED_MEDIA_TYPE */
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
#include "contiki.h"
|
||||
#include "contiki-net.h"
|
||||
#include "er-coap.h"
|
||||
#include "er-coap-engine.h"
|
||||
|
||||
#include "dtls.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "dtls_debug.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static struct dtls_context_t *dtls_ctx = NULL;
|
||||
|
||||
static dtls_handler_t coap_dtls_callback = {
|
||||
.write = coap_dtls_send_to_peer,
|
||||
.read = coap_dtls_read_from_peer,
|
||||
.event = NULL,
|
||||
#ifdef DTLS_PSK
|
||||
.get_psk_info = coap_dtls_get_psk_info,
|
||||
#endif
|
||||
#ifdef DTLS_ECC
|
||||
.get_ecdsa_key = NULL,
|
||||
.verify_ecdsa_key = NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
coap_init_communication_layer(uint16_t port)
|
||||
{
|
||||
struct uip_udp_conn *udp_conn = NULL;
|
||||
|
||||
dtls_init();
|
||||
dtls_set_log_level(DTLS_LOG_DEBUG);
|
||||
|
||||
udp_conn = udp_new(NULL, 0, NULL);
|
||||
udp_bind(udp_conn, port);
|
||||
|
||||
dtls_ctx = dtls_new_context(udp_conn);
|
||||
if(dtls_ctx) {
|
||||
dtls_set_handler(dtls_ctx, &COAP_DTLS_CALLBACK);
|
||||
}
|
||||
/* new connection with remote host */
|
||||
printf("COAP-DTLS listening on port %u\n", uip_ntohs(udp_conn->lport));
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
coap_send_message(uip_ipaddr_t *addr, uint16_t port,
|
||||
uint8_t *data, uint16_t length)
|
||||
{
|
||||
session_t session;
|
||||
|
||||
dtls_session_init(&session);
|
||||
uip_ipaddr_copy(&session.addr, addr);
|
||||
session.port = port;
|
||||
|
||||
dtls_write(dtls_ctx, &session, data, length);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
coap_handle_receive()
|
||||
{
|
||||
session_t session;
|
||||
|
||||
if(uip_newdata()) {
|
||||
dtls_session_init(&session);
|
||||
uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr);
|
||||
session.port = UIP_UDP_BUF->srcport;
|
||||
|
||||
dtls_handle_message(dtls_ctx, &session, uip_appdata, uip_datalen());
|
||||
}
|
||||
}
|
||||
/* DTLS Specific functions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#ifdef DTLS_PSK
|
||||
/* This function is the "key store" for tinyDTLS. It is called to
|
||||
* retrieve a key for the given identiy within this particular
|
||||
* session. */
|
||||
int
|
||||
coap_dtls_get_psk_info(struct dtls_context_t *ctx, const session_t *session,
|
||||
dtls_credentials_type_t type,
|
||||
const unsigned char *id, size_t id_len,
|
||||
unsigned char *result, size_t result_length)
|
||||
{
|
||||
|
||||
struct keymap_t {
|
||||
unsigned char *id;
|
||||
size_t id_length;
|
||||
unsigned char *key;
|
||||
size_t key_length;
|
||||
} psk[1] = {
|
||||
{ (unsigned char *)DTLS_IDENTITY, DTLS_IDENTITY_LENGTH, (unsigned char *)DTLS_PSK_KEY_VALUE, DTLS_PSK_KEY_VALUE_LENGTH },
|
||||
};
|
||||
if(type == DTLS_PSK_IDENTITY) {
|
||||
if(id_len) {
|
||||
dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id);
|
||||
}
|
||||
|
||||
if(result_length < psk[0].id_length) {
|
||||
dtls_warn("cannot set psk_identity -- buffer too small\n");
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
memcpy(result, psk[0].id, psk[0].id_length);
|
||||
return psk[0].id_length;
|
||||
} else if(type == DTLS_PSK_KEY) {
|
||||
if(id) {
|
||||
int i;
|
||||
for(i = 0; i < sizeof(psk) / sizeof(struct keymap_t); i++) {
|
||||
if(id_len == psk[i].id_length && memcmp(id, psk[i].id, id_len) == 0) {
|
||||
if(result_length < psk[i].key_length) {
|
||||
dtls_warn("buffer too small for PSK");
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
memcpy(result, psk[i].key, psk[i].key_length);
|
||||
return psk[i].key_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
|
||||
}
|
||||
#endif
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
int
|
||||
coap_dtls_send_to_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len)
|
||||
{
|
||||
|
||||
struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx);
|
||||
|
||||
uip_ipaddr_copy(&conn->ripaddr, &session->addr);
|
||||
conn->rport = session->port;
|
||||
|
||||
uip_udp_packet_send(conn, data, len);
|
||||
|
||||
/* Restore server connection to allow data from any node */
|
||||
memset(&conn->ripaddr, 0, sizeof(conn->ripaddr));
|
||||
memset(&conn->rport, 0, sizeof(conn->rport));
|
||||
|
||||
return len;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
int
|
||||
coap_dtls_read_from_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len)
|
||||
{
|
||||
uip_len = len;
|
||||
memmove(uip_appdata, data, len);
|
||||
coap_receive(ctx);
|
||||
return 0;
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
#ifndef COAP_DTLS_H_
|
||||
#define COAP_DTLS_H_
|
||||
|
||||
/* Internal configuration of tinydtls for er-coap-dtls */
|
||||
|
||||
#if defined DTLS_CONF_IDENTITY && defined DTLS_CONF_IDENTITY_LENGTH
|
||||
#define DTLS_IDENTITY DTLS_CONF_IDENTITY
|
||||
#define DTLS_IDENTITY_LENGTH DTLS_CONF_IDENTITY_LENGTH
|
||||
#else
|
||||
#define DTLS_IDENTITY "Client_identity"
|
||||
#define DTLS_IDENTITY_LENGTH 15
|
||||
#endif
|
||||
|
||||
#if defined DTLS_CONF_PSK_KEY && defined DTLS_CONF_PSK_KEY_LENGTH
|
||||
#define DTLS_PSK_KEY_VALUE DTLS_CONF_PSK_KEY
|
||||
#define DTLS_PSK_KEY_VALUE_LENGTH DTLS_CONF_PSK_KEY_LENGTH
|
||||
#else
|
||||
#warning "DTLS: Using default secret key !"
|
||||
#define DTLS_PSK_KEY_VALUE "secretPSK"
|
||||
#define DTLS_PSK_KEY_VALUE_LENGTH 9
|
||||
#endif
|
||||
|
||||
/* Structure that hold tinydtls callbacks, has type 'dtls_handler_t'. */
|
||||
#ifndef COAP_DTLS_CALLBACK
|
||||
#ifdef COAP_DTLS_CONF_CALLBACK
|
||||
#define COAP_DTLS_CALLBACK COAP_DTLS_CONF_CALLBACK
|
||||
#else /* COAP_DTLS_CONF_CALLBACK */
|
||||
#define COAP_DTLS_CALLBACK coap_dtls_callback
|
||||
#endif /* COAP_DTLS_CALLBACK */
|
||||
|
||||
/* Send 'data' to peer defined by session */
|
||||
int coap_dtls_send_to_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len);
|
||||
|
||||
/* Read 'data' from peer */
|
||||
int coap_dtls_read_from_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len);
|
||||
#ifdef DTLS_PSK
|
||||
/* Retrieve the key for given identity withing this session */
|
||||
int coap_dtls_get_psk_info(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
dtls_credentials_type_t type,
|
||||
const unsigned char *id, size_t id_len,
|
||||
unsigned char *result, size_t result_length);
|
||||
#endif
|
||||
|
||||
#endif /* COAP_DTLS_H_ */
|
|
@ -41,7 +41,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "er-coap-engine.h"
|
||||
#include "er-coap-communication.h"
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
|
@ -65,8 +64,8 @@ static service_callback_t service_cbk = NULL;
|
|||
/*---------------------------------------------------------------------------*/
|
||||
/*- Internal API ------------------------------------------------------------*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
coap_receive()
|
||||
static int
|
||||
coap_receive(void)
|
||||
{
|
||||
erbium_status_code = NO_ERROR;
|
||||
|
||||
|
@ -347,7 +346,7 @@ PROCESS_THREAD(coap_engine, ev, data)
|
|||
PROCESS_YIELD();
|
||||
|
||||
if(ev == tcpip_event) {
|
||||
coap_handle_receive();
|
||||
coap_receive();
|
||||
} else if(ev == PROCESS_EVENT_TIMER) {
|
||||
/* retransmissions are handled here */
|
||||
coap_check_transactions();
|
||||
|
@ -483,7 +482,6 @@ const struct rest_implementation coap_rest_implementation = {
|
|||
NOT_FOUND_4_04,
|
||||
METHOD_NOT_ALLOWED_4_05,
|
||||
NOT_ACCEPTABLE_4_06,
|
||||
REQUEST_ENTITY_INCOMPLETE_4_08,
|
||||
REQUEST_ENTITY_TOO_LARGE_4_13,
|
||||
UNSUPPORTED_MEDIA_TYPE_4_15,
|
||||
INTERNAL_SERVER_ERROR_5_00,
|
||||
|
|
|
@ -52,7 +52,6 @@ typedef coap_packet_t rest_request_t;
|
|||
typedef coap_packet_t rest_response_t;
|
||||
|
||||
void coap_init_engine(void);
|
||||
int coap_receive();
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*- Client Part -------------------------------------------------------------*/
|
||||
|
|
|
@ -107,7 +107,7 @@ int coap_obs_remove_observee_by_token(uip_ipaddr_t *addr, uint16_t port,
|
|||
int coap_obs_remove_observee_by_url(uip_ipaddr_t *addr, uint16_t port,
|
||||
const char *url);
|
||||
|
||||
void coap_handle_notification(uip_ipaddr_t *addr, uint16_t port,
|
||||
void coap_handle_notification(uip_ipaddr_t *, uint16_t port,
|
||||
coap_packet_t *notification);
|
||||
|
||||
coap_observee_t *coap_obs_request_registration(uip_ipaddr_t *addr,
|
||||
|
|
|
@ -249,8 +249,6 @@ coap_notify_observers_sub(resource_t *resource, const char *subpath)
|
|||
|
||||
if(notification->code < BAD_REQUEST_4_00) {
|
||||
coap_set_header_observe(notification, (obs->obs_counter)++);
|
||||
/* mask out to keep the CoAP observe option length <= 3 bytes */
|
||||
obs->obs_counter &= 0xffffff;
|
||||
}
|
||||
coap_set_token(notification, obs->token, obs->token_len);
|
||||
|
||||
|
@ -268,7 +266,7 @@ coap_observe_handler(resource_t *resource, void *request, void *response)
|
|||
{
|
||||
coap_packet_t *const coap_req = (coap_packet_t *)request;
|
||||
coap_packet_t *const coap_res = (coap_packet_t *)response;
|
||||
coap_observer_t *obs;
|
||||
coap_observer_t * obs;
|
||||
|
||||
if(coap_req->code == COAP_GET && coap_res->code < 128) { /* GET request and response without error code */
|
||||
if(IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) {
|
||||
|
@ -278,8 +276,6 @@ coap_observe_handler(resource_t *resource, void *request, void *response)
|
|||
coap_req->uri_path, coap_req->uri_path_len);
|
||||
if(obs) {
|
||||
coap_set_header_observe(coap_res, (obs->obs_counter)++);
|
||||
/* mask out to keep the CoAP observe option length <= 3 bytes */
|
||||
obs->obs_counter &= 0xffffff;
|
||||
/*
|
||||
* Following payload is for demonstration purposes only.
|
||||
* A subscription should return the same representation as a normal GET.
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
#include "contiki.h"
|
||||
#include "contiki-net.h"
|
||||
#include "er-coap-engine.h"
|
||||
#include "er-coap-communication.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "uip-debug.h"
|
||||
|
||||
static struct uip_udp_conn *udp_conn = NULL;
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
coap_init_communication_layer(uint16_t port)
|
||||
{
|
||||
/* new connection with remote host */
|
||||
udp_conn = udp_new(NULL, 0, NULL);
|
||||
udp_bind(udp_conn, port);
|
||||
PRINTF("Listening on port %u\n", uip_ntohs(udp_conn->lport));
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length)
|
||||
{
|
||||
/* Configure connection to reply to client */
|
||||
uip_ipaddr_copy(&udp_conn->ripaddr, addr);
|
||||
udp_conn->rport = port;
|
||||
|
||||
uip_udp_packet_send(udp_conn, data, length);
|
||||
PRINTF("-sent UDP datagram (%u)-\n", length);
|
||||
|
||||
/* Restore server connection to allow data from any node */
|
||||
memset(&udp_conn->ripaddr, 0, sizeof(udp_conn->ripaddr));
|
||||
udp_conn->rport = 0;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
coap_handle_receive()
|
||||
{
|
||||
coap_receive();
|
||||
}
|
|
@ -44,7 +44,6 @@
|
|||
|
||||
#include "er-coap.h"
|
||||
#include "er-coap-transactions.h"
|
||||
#include "er-coap-communication.h"
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
|
@ -61,6 +60,7 @@
|
|||
/*---------------------------------------------------------------------------*/
|
||||
/*- Variables ---------------------------------------------------------------*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static struct uip_udp_conn *udp_conn = NULL;
|
||||
static uint16_t current_mid = 0;
|
||||
|
||||
coap_status_t erbium_status_code = NO_ERROR;
|
||||
|
@ -279,7 +279,9 @@ void
|
|||
coap_init_connection(uint16_t port)
|
||||
{
|
||||
/* new connection with remote host */
|
||||
coap_init_communication_layer(port);
|
||||
udp_conn = udp_new(NULL, 0, NULL);
|
||||
udp_bind(udp_conn, port);
|
||||
PRINTF("Listening on port %u\n", uip_ntohs(udp_conn->lport));
|
||||
|
||||
/* initialize transaction ID */
|
||||
current_mid = random_rand();
|
||||
|
@ -420,6 +422,23 @@ coap_serialize_message(void *packet, uint8_t *buffer)
|
|||
return (option - buffer) + coap_pkt->payload_len; /* packet length */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data,
|
||||
uint16_t length)
|
||||
{
|
||||
/* configure connection to reply to client */
|
||||
uip_ipaddr_copy(&udp_conn->ripaddr, addr);
|
||||
udp_conn->rport = port;
|
||||
|
||||
uip_udp_packet_send(udp_conn, data, length);
|
||||
|
||||
PRINTF("-sent UDP datagram (%u)-\n", length);
|
||||
|
||||
/* restore server socket to allow data from any node */
|
||||
memset(&udp_conn->ripaddr, 0, sizeof(udp_conn->ripaddr));
|
||||
udp_conn->rport = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
coap_status_t
|
||||
coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
|
||||
{
|
||||
|
@ -510,21 +529,8 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
|
|||
++current_option;
|
||||
}
|
||||
|
||||
if(current_option + option_length > data + data_len) {
|
||||
/* Malformed CoAP - out of bounds */
|
||||
PRINTF("BAD REQUEST: options outside data packet: %u > %u\n",
|
||||
(unsigned)(current_option + option_length - data), data_len);
|
||||
return BAD_REQUEST_4_00;
|
||||
}
|
||||
|
||||
option_number += option_delta;
|
||||
|
||||
if(option_number > COAP_OPTION_SIZE1) {
|
||||
/* Malformed CoAP - out of bounds */
|
||||
PRINTF("BAD REQUEST: option number too large: %u\n", option_number);
|
||||
return BAD_REQUEST_4_00;
|
||||
}
|
||||
|
||||
PRINTF("OPTION %u (delta %u, len %zu): ", option_number, option_delta,
|
||||
option_length);
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
json-resource_src = generic_resource.c
|
|
@ -1,271 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2014-15, Ralf Schlatterbeck Open Source Consulting
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup Generic CoAP Resource Handler
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Generic CoAP Resource Handler
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "contiki.h"
|
||||
#include "jsonparse.h"
|
||||
#include "er-coap.h"
|
||||
#include "generic_resource.h"
|
||||
|
||||
/* Error-handling macro */
|
||||
# define BYE(_exp, _tag) \
|
||||
do { \
|
||||
PRINTF("Expect "_exp": %d\n",_tag); \
|
||||
return -1; \
|
||||
} while(0)
|
||||
|
||||
#define DEBUG 1
|
||||
#if DEBUG
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
|
||||
int8_t
|
||||
json_parse_variable
|
||||
(const uint8_t *bytes, size_t len, char *name, char *buf, size_t buflen)
|
||||
{
|
||||
int tag = 0;
|
||||
struct jsonparse_state state;
|
||||
struct jsonparse_state *parser = &state;
|
||||
PRINTF ("PUT: len: %d, %s\n", len, (const char *)bytes);
|
||||
jsonparse_setup (parser, (const char *)bytes, len);
|
||||
if ((tag = jsonparse_next (parser)) != JSON_TYPE_OBJECT) {
|
||||
BYE ("OBJECT", tag);
|
||||
}
|
||||
if ((tag = jsonparse_next (parser)) != JSON_TYPE_PAIR_NAME) {
|
||||
BYE ("PAIR_NAME", tag);
|
||||
}
|
||||
while (jsonparse_strcmp_value (parser, name) != 0) {
|
||||
tag = jsonparse_next (parser);
|
||||
if (tag != JSON_TYPE_PAIR) {
|
||||
BYE ("PAIR", tag);
|
||||
}
|
||||
tag = jsonparse_next (parser);
|
||||
tag = jsonparse_next (parser);
|
||||
if (tag != ',') {
|
||||
BYE (",", tag);
|
||||
}
|
||||
tag = jsonparse_next (parser);
|
||||
if (tag != JSON_TYPE_PAIR_NAME) {
|
||||
BYE ("PAIR_NAME", tag);
|
||||
}
|
||||
}
|
||||
tag = jsonparse_next (parser);
|
||||
if (tag != JSON_TYPE_PAIR) {
|
||||
BYE ("PAIR", tag);
|
||||
}
|
||||
tag = jsonparse_next (parser);
|
||||
if (tag != JSON_TYPE_STRING) {
|
||||
BYE ("STRING", tag);
|
||||
}
|
||||
jsonparse_copy_value (parser, buf, buflen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *get_uri (void *request)
|
||||
{
|
||||
static char buf [MAX_URI_STRING_LENGTH];
|
||||
const char *uri;
|
||||
size_t len = coap_get_header_uri_path (request, &uri);
|
||||
if (len > sizeof (buf) - 1) {
|
||||
*buf = '\0';
|
||||
} else {
|
||||
strncpy (buf, uri, len);
|
||||
buf [len] = '\0';
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *get_query (void *request)
|
||||
{
|
||||
static char buf [MAX_QUERY_STRING_LENGTH];
|
||||
const char *query;
|
||||
size_t len = coap_get_header_uri_query (request, &query);
|
||||
if (len > sizeof (buf) - 1) {
|
||||
*buf = '\0';
|
||||
} else {
|
||||
strncpy (buf, query, len);
|
||||
buf [len] = '\0';
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void generic_get_handler
|
||||
( void *request
|
||||
, void *response
|
||||
, uint8_t *buffer
|
||||
, uint16_t preferred_size
|
||||
, int32_t *offset
|
||||
, char *name
|
||||
, int is_str
|
||||
, size_t (*to_str)
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf, size_t bsize
|
||||
)
|
||||
)
|
||||
{
|
||||
int success = 1;
|
||||
char temp [MAX_GET_STRING_LENGTH];
|
||||
size_t len = 0;
|
||||
unsigned int accept = -1;
|
||||
const char *uri = get_uri (request);
|
||||
const char *query = get_query (request);
|
||||
|
||||
REST.get_header_accept (request, &accept);
|
||||
if ( accept != -1
|
||||
&& accept != REST.type.TEXT_PLAIN
|
||||
&& accept != REST.type.APPLICATION_JSON
|
||||
)
|
||||
{
|
||||
success = 0;
|
||||
REST.set_response_status (response, REST.status.NOT_ACCEPTABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
// TEXT format
|
||||
if (accept == REST.type.APPLICATION_JSON) {
|
||||
len += snprintf
|
||||
( temp + len
|
||||
, sizeof (temp) - len
|
||||
, "{\n \"%s\" : %s"
|
||||
, name
|
||||
, is_str ? "\"" : ""
|
||||
);
|
||||
if (len > sizeof (temp)) {
|
||||
success = 0;
|
||||
goto out;
|
||||
}
|
||||
len += to_str (name, uri, query, temp + len, sizeof (temp) - len);
|
||||
if (len > sizeof (temp)) {
|
||||
success = 0;
|
||||
goto out;
|
||||
}
|
||||
len += snprintf
|
||||
( temp + len
|
||||
, sizeof (temp) - len
|
||||
, "%s\n}\n"
|
||||
, is_str ? "\"" : ""
|
||||
);
|
||||
if (len > sizeof (temp)) {
|
||||
success = 0;
|
||||
goto out;
|
||||
}
|
||||
} else { // TEXT Format
|
||||
len += to_str (name, uri, query, temp + len, sizeof (temp) - len);
|
||||
if (len > sizeof (temp)) {
|
||||
success = 0;
|
||||
goto out;
|
||||
}
|
||||
len += snprintf (temp + len, sizeof (temp) - len, "\n");
|
||||
if (len > sizeof (temp)) {
|
||||
success = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
memcpy (buffer, temp, len);
|
||||
REST.set_header_content_type (response, accept);
|
||||
REST.set_response_payload (response, buffer, len);
|
||||
out :
|
||||
if (!success) {
|
||||
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
void generic_put_handler
|
||||
( void *request
|
||||
, void *response
|
||||
, uint8_t *buffer
|
||||
, uint16_t preferred_size
|
||||
, int32_t *offset
|
||||
, char *name
|
||||
, int (*from_str)
|
||||
(const char *name, const char *uri, const char *query, const char *s)
|
||||
)
|
||||
{
|
||||
int success = 1;
|
||||
char temp [100];
|
||||
size_t len = 0;
|
||||
const uint8_t *bytes = NULL;
|
||||
unsigned int c_ctype;
|
||||
const char *uri = get_uri (request);
|
||||
const char *query = get_query (request);
|
||||
REST.get_header_content_type (request, &c_ctype);
|
||||
|
||||
if (from_str && (len = coap_get_payload (request, &bytes))) {
|
||||
if (c_ctype == REST.type.TEXT_PLAIN) {
|
||||
int l = MIN (len, sizeof (temp) - 1);
|
||||
temp [sizeof (temp) - 1] = 0;
|
||||
strncpy (temp, (const char *)bytes, l);
|
||||
temp [l] = 0;
|
||||
} else { // jSON Format
|
||||
if (json_parse_variable (bytes, len, name, temp, sizeof (temp)) < 0) {
|
||||
success = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (from_str (name, uri, query, temp) < 0) {
|
||||
success = 0;
|
||||
} else {
|
||||
REST.set_response_status (response, REST.status.CHANGED);
|
||||
}
|
||||
} else {
|
||||
success = 0;
|
||||
}
|
||||
out:
|
||||
if (!success) {
|
||||
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* VI settings, see coding style
|
||||
* ex:ts=8:et:sw=2
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2014-15, Ralf Schlatterbeck Open Source Consulting
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup Generic CoAP Resource Handler
|
||||
*
|
||||
* This factors the boilerplate code necessary for defining a resource
|
||||
* together with the necessary handler. Currently this supports
|
||||
* text/plain and application/json and outputs the resource with its
|
||||
* name in json format. This may change in the future as more CoRE
|
||||
* standards (e.g. see RFC 6690) get defined.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Generic CoAP Resource Handler
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*/
|
||||
|
||||
#define STR__(s) #s
|
||||
#define STR_(s) STR__(s)
|
||||
|
||||
#define MAX_GET_STRING_LENGTH 100
|
||||
#define MAX_URI_STRING_LENGTH 30
|
||||
#define MAX_QUERY_STRING_LENGTH 30
|
||||
|
||||
/*
|
||||
* A macro that extends the resource definition and also sets up the
|
||||
* necessary handler function that calls format/parse routines that
|
||||
* convert from/to string (fs and ts). The ts function needs to return
|
||||
* the length written, similar to sprintf.
|
||||
* The content type definitions ct="0 5" are text/plain and
|
||||
* application/json, respectively, see rfc7252 Table 9 p. 91.
|
||||
* Yes, this *is* a hack. But I hate boilerplate code.
|
||||
*/
|
||||
|
||||
#define GENERIC_RESOURCE(name, title, unit, is_str, fs, ts) \
|
||||
static void name##_get_handler \
|
||||
( void *request \
|
||||
, void *response \
|
||||
, uint8_t *buffer \
|
||||
, uint16_t ps \
|
||||
, int32_t *offset \
|
||||
) \
|
||||
{ \
|
||||
generic_get_handler \
|
||||
(request, response, buffer, ps, offset, STR_(name), is_str, ts); \
|
||||
} \
|
||||
static void name##_put_handler \
|
||||
( void *request \
|
||||
, void *response \
|
||||
, uint8_t *buffer \
|
||||
, uint16_t ps \
|
||||
, int32_t *offset \
|
||||
) \
|
||||
{ \
|
||||
generic_put_handler \
|
||||
(request, response, buffer, ps, offset, STR_(name), fs); \
|
||||
} \
|
||||
\
|
||||
RESOURCE ( res_##name \
|
||||
, "title=\"" STR_(title) "\"" \
|
||||
";rt=UCUM:\"" STR_(unit) "\"" \
|
||||
";ct=\"0 5\"" \
|
||||
, (ts) ? name##_get_handler : NULL \
|
||||
, NULL /* POST */ \
|
||||
, (fs) ? name##_put_handler : NULL \
|
||||
, NULL /* DELETE */ \
|
||||
)
|
||||
|
||||
/* Ignore constant pointer tests above */
|
||||
#pragma GCC diagnostic ignored "-Waddress"
|
||||
|
||||
/**
|
||||
* \brief Parse a resource in json format
|
||||
* \param bytes: Input string received via coap
|
||||
* \param len: Length of input string
|
||||
* \param name: Name to search in json input
|
||||
* \param buf: Output buffer
|
||||
* \param buflen: Output buffer length
|
||||
* \return 0 for success, -1 for error
|
||||
*
|
||||
* If compiled with DEBUG also prints the error encountered
|
||||
*/
|
||||
extern int8_t json_parse_variable
|
||||
(const uint8_t *bytes, size_t len, char *name, char *buf, size_t buflen);
|
||||
|
||||
/**
|
||||
* \brief Generic coap GET resource handler
|
||||
* \param name: The name of the variable in json
|
||||
* \param to_str: Application method to format value for output;
|
||||
* the function may chose to format differently for coap or text
|
||||
* The other parameters are the same as a normal resource handler
|
||||
* This helps avoid boilerplate code for request handlers
|
||||
*
|
||||
* The callback functions get the name of the parameter as a first
|
||||
* argument, this allows to re-use the same function for different
|
||||
* parameters. In addition it gets a buffer and the size of the buffer.
|
||||
* It needs to return the number of bytes output, similar to sprintf.
|
||||
*/
|
||||
extern void generic_get_handler
|
||||
( void *request
|
||||
, void *response
|
||||
, uint8_t *buffer
|
||||
, uint16_t preferred_size
|
||||
, int32_t *offset
|
||||
, char *name
|
||||
, int is_str
|
||||
, size_t (*to_str)
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* \brief Generic coap PUT resource handler
|
||||
* \param name: The name of the variable in json
|
||||
* \param from_str: Application method to parse value from string
|
||||
* and act on it, may be NULL in which case the resource only
|
||||
* supports GET not PUT
|
||||
* The other parameters are the same as a normal resource handler
|
||||
* This helps avoid boilerplate code for request handlers
|
||||
*
|
||||
* The callback functions get the name of the parameter as a first
|
||||
* argument, this allows to re-use the same function for different
|
||||
* parameters. The from_str in addition gets the string to parse.
|
||||
*/
|
||||
extern void generic_put_handler
|
||||
( void *request
|
||||
, void *response
|
||||
, uint8_t *buffer
|
||||
, uint16_t preferred_size
|
||||
, int32_t *offset
|
||||
, char *name
|
||||
, int (*from_str)
|
||||
(const char *name, const char *uri, const char *query, const char *s)
|
||||
);
|
||||
|
||||
/*
|
||||
* VI settings, see coding style
|
||||
* ex:ts=8:et:sw=2
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
|
|
@ -130,7 +130,6 @@ typedef enum {
|
|||
/*---------------------------------------------------------------------------*/
|
||||
/* Protothread send macros */
|
||||
#define PT_MQTT_WRITE_BYTES(conn, data, len) \
|
||||
conn->out_write_pos = 0; \
|
||||
while(write_bytes(conn, data, len)) { \
|
||||
PT_WAIT_UNTIL(pt, (conn)->out_buffer_sent); \
|
||||
}
|
||||
|
@ -148,19 +147,15 @@ typedef enum {
|
|||
*/
|
||||
#define PT_MQTT_WAIT_SEND() \
|
||||
do { \
|
||||
if (PROCESS_ERR_OK == \
|
||||
process_post(PROCESS_CURRENT(), mqtt_continue_send_event, NULL)) { \
|
||||
do { \
|
||||
process_post(PROCESS_CURRENT(), mqtt_continue_send_event, NULL); \
|
||||
PROCESS_WAIT_EVENT(); \
|
||||
if(ev == mqtt_abort_now_event) { \
|
||||
conn->state = MQTT_CONN_STATE_ABORT_IMMEDIATE; \
|
||||
PT_INIT(&conn->out_proto_thread); \
|
||||
PT_EXIT(&conn->out_proto_thread); \
|
||||
process_post(PROCESS_CURRENT(), ev, data); \
|
||||
} else if(ev >= mqtt_event_min && ev <= mqtt_event_max) { \
|
||||
process_post(PROCESS_CURRENT(), ev, data); \
|
||||
} \
|
||||
} while (ev != mqtt_continue_send_event); \
|
||||
} \
|
||||
} while(0)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static process_event_t mqtt_do_connect_tcp_event;
|
||||
|
@ -756,8 +751,6 @@ handle_connack(struct mqtt_connection *conn)
|
|||
call_event(conn,
|
||||
MQTT_EVENT_CONNECTION_REFUSED_ERROR,
|
||||
&conn->in_packet.payload[1]);
|
||||
abort_connection(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->out_packet.qos_state = MQTT_QOS_STATE_GOT_ACK;
|
||||
|
@ -1193,8 +1186,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
|||
if(conn->state == MQTT_CONN_STATE_SENDING_MQTT_DISCONNECT) {
|
||||
if(conn->out_buffer_sent == 1) {
|
||||
PT_INIT(&conn->out_proto_thread);
|
||||
while(conn->state != MQTT_CONN_STATE_ABORT_IMMEDIATE &&
|
||||
disconnect_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||
while(disconnect_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
||||
conn->state != MQTT_CONN_STATE_ABORT_IMMEDIATE) {
|
||||
PT_MQTT_WAIT_SEND();
|
||||
}
|
||||
abort_connection(conn);
|
||||
|
@ -1211,8 +1204,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
|||
if(conn->out_buffer_sent == 1 &&
|
||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||
PT_INIT(&conn->out_proto_thread);
|
||||
while(conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER &&
|
||||
pingreq_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||
while(pingreq_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||
PT_MQTT_WAIT_SEND();
|
||||
}
|
||||
}
|
||||
|
@ -1224,8 +1217,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
|||
if(conn->out_buffer_sent == 1 &&
|
||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||
PT_INIT(&conn->out_proto_thread);
|
||||
while(conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER &&
|
||||
subscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||
while(subscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||
PT_MQTT_WAIT_SEND();
|
||||
}
|
||||
}
|
||||
|
@ -1237,8 +1230,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
|||
if(conn->out_buffer_sent == 1 &&
|
||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||
PT_INIT(&conn->out_proto_thread);
|
||||
while(conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER &&
|
||||
unsubscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||
while(unsubscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||
PT_MQTT_WAIT_SEND();
|
||||
}
|
||||
}
|
||||
|
@ -1250,8 +1243,8 @@ PROCESS_THREAD(mqtt_process, ev, data)
|
|||
if(conn->out_buffer_sent == 1 &&
|
||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||
PT_INIT(&conn->out_proto_thread);
|
||||
while(conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER &&
|
||||
publish_pt(&conn->out_proto_thread, conn) < PT_EXITED) {
|
||||
while(publish_pt(&conn->out_proto_thread, conn) < PT_EXITED &&
|
||||
conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) {
|
||||
PT_MQTT_WAIT_SEND();
|
||||
}
|
||||
}
|
||||
|
@ -1338,9 +1331,7 @@ mqtt_connect(struct mqtt_connection *conn, char *host, uint16_t port,
|
|||
conn->connect_vhdr_flags |= MQTT_VHDR_CLEAN_SESSION_FLAG;
|
||||
|
||||
/* convert the string IPv6 address to a numeric IPv6 address */
|
||||
if(uiplib_ip6addrconv(host, &ip6addr) == 0) {
|
||||
return MQTT_STATUS_ERROR;
|
||||
}
|
||||
uiplib_ip6addrconv(host, &ip6addr);
|
||||
|
||||
uip_ipaddr_copy(&(conn->server_ip), ipaddr);
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ typedef enum {
|
|||
MQTT_CONN_STATE_ERROR,
|
||||
MQTT_CONN_STATE_DNS_ERROR,
|
||||
MQTT_CONN_STATE_DISCONNECTING,
|
||||
MQTT_CONN_STATE_ABORT_IMMEDIATE,
|
||||
|
||||
MQTT_CONN_STATE_NOT_CONNECTED,
|
||||
MQTT_CONN_STATE_DNS_LOOKUP,
|
||||
MQTT_CONN_STATE_TCP_CONNECTING,
|
||||
|
@ -204,6 +204,7 @@ typedef enum {
|
|||
MQTT_CONN_STATE_CONNECTING_TO_BROKER,
|
||||
MQTT_CONN_STATE_CONNECTED_TO_BROKER,
|
||||
MQTT_CONN_STATE_SENDING_MQTT_DISCONNECT,
|
||||
MQTT_CONN_STATE_ABORT_IMMEDIATE,
|
||||
} mqtt_conn_state_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct mqtt_string {
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ota-update_src = res_bootloader.c res_reboot.c res_upload_image.c
|
|
@ -1,22 +0,0 @@
|
|||
extern resource_t res_upload_image;
|
||||
extern resource_t res_part_count;
|
||||
extern resource_t res_part_size;
|
||||
extern resource_t res_boot_default;
|
||||
extern resource_t res_boot_next;
|
||||
extern resource_t res_active_part;
|
||||
extern resource_t res_part_start;
|
||||
extern resource_t res_part_ok;
|
||||
extern resource_t res_reboot;
|
||||
|
||||
#define OTA_ACTIVATE_RESOURCES() \
|
||||
static char resname[] = "ota/update";\
|
||||
rest_activate_resource (&res_upload_image, resname);\
|
||||
rest_activate_resource (&res_part_count, (char *)"ota/part_count");\
|
||||
rest_activate_resource (&res_part_size, (char *)"ota/part_size");\
|
||||
rest_activate_resource (&res_boot_default, (char *)"ota/boot_default");\
|
||||
rest_activate_resource (&res_boot_next, (char *)"ota/boot_next");\
|
||||
rest_activate_resource (&res_active_part, (char *)"ota/active_part");\
|
||||
rest_activate_resource (&res_part_start, (char *)"ota/part_start");\
|
||||
rest_activate_resource (&res_part_ok, (char *)"ota/part_ok");\
|
||||
rest_activate_resource (&res_reboot, (char *)"ota/reboot");
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Ralf Schlatterbeck Open Source Consulting
|
||||
* 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Bootloader ressources
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "contiki.h"
|
||||
#include "contiki-net.h"
|
||||
#include "rest-engine.h"
|
||||
#include "er-coap-engine.h"
|
||||
#include "uiplib.h"
|
||||
#include "generic_resource.h"
|
||||
#include "bootloader_if.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
/*
|
||||
* Resources to be activated need to be imported through the extern keyword.
|
||||
* The build system automatically compiles the resources in the
|
||||
* corresponding sub-directory.
|
||||
*/
|
||||
|
||||
static size_t
|
||||
part_count
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
return snprintf (buf, bsize, "%ld", bootloader_get_part_count ());
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( part_count
|
||||
, Partition Count
|
||||
, count
|
||||
, 0
|
||||
, NULL
|
||||
, part_count
|
||||
);
|
||||
|
||||
static size_t
|
||||
part_size
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
return snprintf (buf, bsize, "%ld", bootloader_get_part_size ());
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( part_size
|
||||
, Partition Size
|
||||
, count
|
||||
, 0
|
||||
, NULL
|
||||
, part_size
|
||||
);
|
||||
|
||||
static size_t
|
||||
get_boot_default
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
return snprintf (buf, bsize, "%ld", bootloader_get_boot_default ());
|
||||
}
|
||||
|
||||
static int
|
||||
set_boot_default
|
||||
(const char *name, const char *uri, const char *query, const char *s)
|
||||
{
|
||||
uint32_t tmp = strtoul (s, NULL, 10);
|
||||
bootloader_set_boot_default (tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( boot_default
|
||||
, Default boot partition
|
||||
, count
|
||||
, 0
|
||||
, set_boot_default
|
||||
, get_boot_default
|
||||
);
|
||||
|
||||
static size_t
|
||||
get_boot_next
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
return snprintf (buf, bsize, "%ld", bootloader_get_boot_next ());
|
||||
}
|
||||
|
||||
static int
|
||||
set_boot_next
|
||||
(const char *name, const char *uri, const char *query, const char *s)
|
||||
{
|
||||
uint32_t tmp = strtoul (s, NULL, 10);
|
||||
bootloader_set_boot_next (tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( boot_next
|
||||
, Next boot partition
|
||||
, count
|
||||
, 0
|
||||
, set_boot_next
|
||||
, get_boot_next
|
||||
);
|
||||
|
||||
static size_t
|
||||
get_active_part
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
return snprintf (buf, bsize, "%ld", bootloader_get_active_part ());
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( active_part
|
||||
, Currently active partition
|
||||
, count
|
||||
, 0
|
||||
, NULL
|
||||
, get_active_part
|
||||
);
|
||||
|
||||
/*
|
||||
* Parse query info. We insist that the query starts with 'part='
|
||||
* Then we parse the integer following the part= string and return the
|
||||
* number. The number is always positive, if something goes wrong we
|
||||
* return a negative number.
|
||||
*/
|
||||
static int get_query_partition (const char *query)
|
||||
{
|
||||
if (strncmp (query, "part=", 5)) {
|
||||
return -1;
|
||||
}
|
||||
return strtoul (query + 5, NULL, 10);
|
||||
}
|
||||
|
||||
static size_t
|
||||
get_part_start
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
int idx = get_query_partition (query);
|
||||
if (idx < 0) {
|
||||
return snprintf (buf, bsize, "Invalid: \"%s\" use part=N query", query);
|
||||
}
|
||||
return snprintf (buf, bsize, "%ld", bootloader_get_part_start (idx));
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( part_start
|
||||
, Start of partition
|
||||
, count
|
||||
, 0
|
||||
, NULL
|
||||
, get_part_start
|
||||
);
|
||||
|
||||
static int
|
||||
set_part_ok
|
||||
(const char *name, const char *uri, const char *query, const char *s)
|
||||
{
|
||||
uint32_t tmp = strtoul (s, NULL, 10);
|
||||
int idx = get_query_partition (query);
|
||||
if (idx < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (tmp) {
|
||||
bootloader_set_part_ok (idx);
|
||||
} else {
|
||||
bootloader_clr_part_ok (idx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
get_part_ok
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
int idx = get_query_partition (query);
|
||||
if (idx < 0) {
|
||||
return snprintf (buf, bsize, "Invalid: \"%s\" use part=N query", query);
|
||||
}
|
||||
return snprintf (buf, bsize, "%ld", bootloader_get_part_ok (idx));
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( part_ok
|
||||
, Set/Clear Partition OK flag
|
||||
, count
|
||||
, 0
|
||||
, set_part_ok
|
||||
, get_part_ok
|
||||
);
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Marcus Priesch Open Source Consulting
|
||||
* 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Reboot ressource
|
||||
* \author
|
||||
* Marcus Priesch <marcus@priesch.co.at>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "contiki.h"
|
||||
#include "er-coap-engine.h"
|
||||
#include "generic_resource.h"
|
||||
#include "dev/watchdog.h"
|
||||
|
||||
PROCESS(reboot_process, "reboot");
|
||||
PROCESS_THREAD(reboot_process, ev, data)
|
||||
{
|
||||
static struct etimer etimer;
|
||||
|
||||
//PROCESS_EXITHANDLER(leds_off(LEDS_ALL);)
|
||||
|
||||
PROCESS_BEGIN();
|
||||
|
||||
//shell_output_str(&reboot_command,
|
||||
// "Rebooting the node in four seconds...", "");
|
||||
|
||||
etimer_set(&etimer, CLOCK_SECOND * 4);
|
||||
PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
||||
//leds_on(LEDS_RED);
|
||||
//etimer_reset(&etimer);
|
||||
//PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
||||
//leds_on(LEDS_GREEN);
|
||||
//etimer_reset(&etimer);
|
||||
//PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
||||
//leds_on(LEDS_BLUE);
|
||||
//etimer_reset(&etimer);
|
||||
//PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
||||
|
||||
watchdog_reboot();
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static size_t
|
||||
get_reboot
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
return snprintf (buf, bsize, "put 'OK' to reboot.");
|
||||
}
|
||||
|
||||
static int
|
||||
do_reboot
|
||||
(const char *name, const char *uri, const char *query, const char *s)
|
||||
{
|
||||
if (strncmp (s, "OK", 2) == 0) {
|
||||
process_start (&reboot_process, NULL);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( reboot
|
||||
, Reboot node
|
||||
, count
|
||||
, 0
|
||||
, do_reboot
|
||||
, get_reboot
|
||||
);
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017, Marcus Priesch, Ralf Schlatterbeck
|
||||
* with code from the res-plugtest-large-update.c by
|
||||
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
|
||||
* 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Over-the-air update using blockwise transfer
|
||||
* \author
|
||||
* Marcus Priesch <marcus@priesch.co.at>
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "sys/cc.h"
|
||||
#include "rest-engine.h"
|
||||
#include "er-coap.h"
|
||||
#include "contiki.h"
|
||||
#include "contiki-net.h"
|
||||
#include "er-coap.h"
|
||||
#include "Arduino.h"
|
||||
#include <avr/interrupt.h>
|
||||
#include "bootloader_if.h"
|
||||
|
||||
#if 1
|
||||
#include <stdio.h>
|
||||
#define PRINTF(x) printf x
|
||||
#else
|
||||
#define PRINTF(x)
|
||||
#endif
|
||||
|
||||
|
||||
// We allocate this statically, otherwise we cannot flash a new image
|
||||
// when ram is exhausted!
|
||||
static uint8_t current_page [256];
|
||||
static uint32_t current_offset = 0;
|
||||
#define PAGESIZE (sizeof (current_page))
|
||||
|
||||
/*
|
||||
* Note that the current code relies on the fact that the bootloader
|
||||
* used only supports two images. This may change in the future. We
|
||||
* mainly need to relax some of the checks and use a different algorithm
|
||||
* for computing imgidx, the index of the partition to be overwritten.
|
||||
* If the bootloader supports more than two partitions at some point we
|
||||
* may want the uploader to explicitly define the partition to be used.
|
||||
*/
|
||||
|
||||
static void
|
||||
res_put_handler
|
||||
( void *request
|
||||
, void *response
|
||||
, uint8_t *buffer
|
||||
, uint16_t preferred_size
|
||||
, int32_t *offset
|
||||
)
|
||||
{
|
||||
coap_packet_t *const packet = (coap_packet_t *)request;
|
||||
uint8_t *in_data = NULL;
|
||||
size_t len = 0;
|
||||
uint32_t partition_start = 0;
|
||||
const uint32_t partition_size = bootloader_get_part_size ();
|
||||
uint32_t imgidx = 0;
|
||||
unsigned int ct = -1;
|
||||
|
||||
/* If the currently-booted partition is not the default partition we
|
||||
* do not allow overwriting a partition: Neither the currently-booted
|
||||
* one (this would crash) nor the only partition that is marked
|
||||
* bootable. We also insist that boot_next == boot_default.
|
||||
*/
|
||||
if (bootloader_get_boot_default () != bootloader_get_boot_next ()) {
|
||||
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||
const char *error_msg = "Won't overwrite boot_next";
|
||||
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||
return;
|
||||
}
|
||||
if (bootloader_get_boot_default () != bootloader_get_active_part ()) {
|
||||
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||
const char *error_msg = "Won't overwrite current";
|
||||
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||
return;
|
||||
}
|
||||
imgidx = !bootloader_get_active_part ();
|
||||
partition_start = bootloader_get_part_start (imgidx);
|
||||
|
||||
REST.get_header_content_type (request, &ct);
|
||||
|
||||
/* Require content_type APPLICATION_OCTET_STREAM */
|
||||
if (ct != REST.type.APPLICATION_OCTET_STREAM) {
|
||||
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||
const char *error_msg = "ContentType";
|
||||
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||
return;
|
||||
}
|
||||
|
||||
len = REST.get_request_payload (request, (const uint8_t **)&in_data);
|
||||
PRINTF (("cur: %lu len: %lu, offset: %lu\n",
|
||||
(uint32_t)current_offset, (uint32_t)len, (uint32_t)*offset));
|
||||
PRINTF (("b1-offs: %lu, b1-size: %u, b1-num: %lu b1-more: %d b1-size1: %lu\n",
|
||||
packet->block1_offset, packet->block1_size, packet->block1_num,
|
||||
packet->block1_more, packet->size1));
|
||||
if (len == 0 || NULL == in_data) {
|
||||
REST.set_response_status (response, REST.status.BAD_REQUEST);
|
||||
const char *error_msg = "NoPayload";
|
||||
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||
return;
|
||||
}
|
||||
|
||||
/* if the block1_offset is 0 a new transmission has started */
|
||||
if (!packet->block1_offset) {
|
||||
current_offset = 0;
|
||||
}
|
||||
|
||||
if (packet->block1_offset > current_offset) {
|
||||
REST.set_response_status (response, REST.status.REQUEST_ENTITY_INCOMPLETE);
|
||||
const char *error_msg = "OutOfSequence";
|
||||
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Old packet or retransmission, immediately confirm */
|
||||
if (packet->block1_offset && packet->block1_offset + len <= current_offset) {
|
||||
REST.set_response_status (response, REST.status.CHANGED);
|
||||
coap_set_header_block1
|
||||
(response, packet->block1_num, 0, packet->block1_size);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: blocksize may be larger than our flash page size
|
||||
if (len > PAGESIZE) {
|
||||
REST.set_response_status (response, REST.status.INTERNAL_SERVER_ERROR);
|
||||
const char *error_msg = "GRMPF: PageSize";
|
||||
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||
return;
|
||||
}
|
||||
// FIXME: blocksize may be larger than our flash page size
|
||||
// So we should handle this case and repeatedly flash a block until the
|
||||
// received data is written.
|
||||
if (current_offset % PAGESIZE + len > PAGESIZE) {
|
||||
REST.set_response_status (response, REST.status.INTERNAL_SERVER_ERROR);
|
||||
const char *error_msg = "GRMPF: blocksize";
|
||||
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||
return;
|
||||
}
|
||||
// Should never happen, we test for < and > earlier.
|
||||
if (packet->block1_offset != current_offset) {
|
||||
REST.set_response_status (response, REST.status.INTERNAL_SERVER_ERROR);
|
||||
const char *error_msg = "GRMPF: Offset";
|
||||
REST.set_response_payload (response, error_msg, strlen (error_msg));
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet->block1_offset + len > partition_size) {
|
||||
REST.set_response_status
|
||||
(response, REST.status.REQUEST_ENTITY_TOO_LARGE);
|
||||
REST.set_response_payload
|
||||
(response, buffer, sprintf ((char *)buffer, "%luB max.", partition_size));
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (current_page + current_offset % PAGESIZE, in_data, len);
|
||||
/* Whenever an upload is started for a partition mark it as not ok */
|
||||
if (current_offset == 0) {
|
||||
PRINTF (("Clear partition_ok: %ld\n", imgidx));
|
||||
bootloader_clr_part_ok (imgidx);
|
||||
}
|
||||
current_offset += len;
|
||||
|
||||
if (current_offset % PAGESIZE == 0) {
|
||||
uint32_t dst_address = partition_start + current_offset - PAGESIZE;
|
||||
/* Special case: Flash irq vectors to backup position */
|
||||
if (current_offset - PAGESIZE < PART_IRQVEC_SIZE) {
|
||||
/* Only for images not at position 0 write first PART_IRQVEC_SIZE
|
||||
* bytes also to original position. For partition 0 it will be
|
||||
* copied there anyway *and* we would crash if we wrote to the
|
||||
* active memory!
|
||||
*/
|
||||
if (partition_start != 0) {
|
||||
PRINTF (("Flashing: %lx to %lx\n", (uint32_t)PAGESIZE, dst_address));
|
||||
bootloader_write_page_to_flash (dst_address, PAGESIZE, current_page);
|
||||
}
|
||||
/* Note: The partition_size returned by the bootloader does *NOT*
|
||||
* include the PART_IRQVEC_SIZE
|
||||
*/
|
||||
dst_address = partition_start + partition_size
|
||||
+ current_offset - PAGESIZE;
|
||||
}
|
||||
PRINTF (("Flashing: %lx to %lx\n", (uint32_t)PAGESIZE, dst_address));
|
||||
bootloader_write_page_to_flash (dst_address, PAGESIZE, current_page);
|
||||
} else if (!packet->block1_more) {
|
||||
uint32_t dst_address =
|
||||
partition_start + (current_offset / PAGESIZE) * PAGESIZE;
|
||||
PRINTF (("Flashing: last %lx to %lx\n", (uint32_t)PAGESIZE, dst_address));
|
||||
bootloader_write_page_to_flash (dst_address, PAGESIZE, current_page);
|
||||
}
|
||||
|
||||
|
||||
if (!packet->block1_more) {
|
||||
// we are finished
|
||||
bootloader_set_boot_next (imgidx);
|
||||
current_offset = 0;
|
||||
}
|
||||
|
||||
REST.set_response_status (response, REST.status.CHANGED);
|
||||
coap_set_header_block1 (response, packet->block1_num, 0, packet->block1_size);
|
||||
}
|
||||
|
||||
RESOURCE(
|
||||
res_upload_image
|
||||
, "title=\"Flash memory upgrade\";rt=\"block\""
|
||||
, NULL
|
||||
, NULL
|
||||
, res_put_handler
|
||||
, NULL
|
||||
);
|
||||
|
|
@ -56,7 +56,6 @@ struct rest_implementation_status {
|
|||
const unsigned int NOT_FOUND; /* NOT_FOUND_4_04, NOT_FOUND_404 */
|
||||
const unsigned int METHOD_NOT_ALLOWED; /* METHOD_NOT_ALLOWED_4_05, METHOD_NOT_ALLOWED_405 */
|
||||
const unsigned int NOT_ACCEPTABLE; /* NOT_ACCEPTABLE_4_06, NOT_ACCEPTABLE_406 */
|
||||
const unsigned int REQUEST_ENTITY_INCOMPLETE; /* REQUEST_ENTITY_INCOMPLETE_4_08, REQUEST_ENTITY_INCOMPLETE_408 */
|
||||
const unsigned int REQUEST_ENTITY_TOO_LARGE; /* REQUEST_ENTITY_TOO_LARGE_4_13, REQUEST_ENTITY_TOO_LARGE_413 */
|
||||
const unsigned int UNSUPPORTED_MEDIA_TYPE; /* UNSUPPORTED_MEDIA_TYPE_4_15, UNSUPPORTED_MEDIA_TYPE_415 */
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "arduino-process.h"
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(serial_shell_process, "Contiki serial shell");
|
||||
|
@ -58,8 +58,6 @@ void
|
|||
shell_default_output(const char *text1, int len1, const char *text2, int len2)
|
||||
{
|
||||
int i;
|
||||
|
||||
mcu_sleep_disable();
|
||||
if(text1 == NULL) {
|
||||
text1 = "";
|
||||
len1 = 0;
|
||||
|
@ -91,7 +89,6 @@ void
|
|||
shell_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(serial_shell_process, ev, data)
|
||||
{
|
||||
|
@ -101,7 +98,6 @@ PROCESS_THREAD(serial_shell_process, ev, data)
|
|||
|
||||
while(1) {
|
||||
PROCESS_WAIT_EVENT_UNTIL(ev == serial_line_event_message && data != NULL);
|
||||
mcu_sleep_disable();
|
||||
shell_input(data, strlen(data));
|
||||
}
|
||||
|
||||
|
|
|
@ -66,11 +66,3 @@ endif
|
|||
ifeq ($(TARGET),z1)
|
||||
shell_src += shell-sky.c shell-exec.c
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),osd-merkur-256)
|
||||
shell_src += shell-merkur.c
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),osd-merkur-128)
|
||||
shell_src += shell-merkur.c
|
||||
endif
|
||||
|
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Merkurboard-specific Contiki shell commands
|
||||
* \author
|
||||
* Harald Pichler <harald@the-develop.net>
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* strtol */
|
||||
#include "sys/cc.h"
|
||||
#include "dev/radio.h"
|
||||
#include "shell-merkur.h"
|
||||
#include "params.h"
|
||||
#include "arduino-process.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(shell_txpower_process, "txpower");
|
||||
SHELL_COMMAND(txpower_command,
|
||||
"txpower",
|
||||
"txpower <power>: change transmission power 0 (3dbm, default) to 15 (-17.2dbm)",
|
||||
&shell_txpower_process);
|
||||
PROCESS(shell_panid_process, "panid");
|
||||
SHELL_COMMAND(panid_command,
|
||||
"panid",
|
||||
"panid <0xabcd>: change panid (default 0xabcd)",
|
||||
&shell_panid_process);
|
||||
PROCESS(shell_rfchannel_process, "rfchannel");
|
||||
SHELL_COMMAND(rfchannel_command,
|
||||
"rfchannel",
|
||||
"rfchannel <channel>: change radio channel (11 - 26)",
|
||||
&shell_rfchannel_process);
|
||||
PROCESS(shell_ccathresholds_process, "ccathresholds");
|
||||
SHELL_COMMAND(ccathresholds_command,
|
||||
"ccathresholds",
|
||||
"ccathresholds <threshold: change cca thresholds -91 to -61 dBm (default -77)",
|
||||
&shell_ccathresholds_process);
|
||||
PROCESS(shell_macconf_process, "macconf");
|
||||
SHELL_COMMAND(macconf_command,
|
||||
"macconf",
|
||||
"macconf <conf>: change mac layer 0 -> do nothing; 1 -> Radio allways on",
|
||||
&shell_macconf_process);
|
||||
PROCESS(shell_saverfparam_process, "saverfparam");
|
||||
SHELL_COMMAND(saverfparam_command,
|
||||
"saverfparam",
|
||||
"saverfparam <> save radio parameters txpower, channel, panid to eeprom settingsmanager",
|
||||
&shell_saverfparam_process);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(shell_txpower_process, ev, data)
|
||||
{
|
||||
radio_value_t value;
|
||||
char buf[10];
|
||||
const char *newptr;
|
||||
PROCESS_BEGIN();
|
||||
|
||||
value = shell_strtolong(data, &newptr);
|
||||
|
||||
/* If no transmission power was given on the command line, we print
|
||||
out the current txpower. */
|
||||
if(newptr == data) {
|
||||
if(get_param(RADIO_PARAM_TXPOWER, &value) == RADIO_RESULT_OK) {
|
||||
}
|
||||
} else {
|
||||
set_param(RADIO_PARAM_TXPOWER, value);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%3d", value);
|
||||
shell_output_str(&txpower_command, "TX Power: ", buf);
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(shell_rfchannel_process, ev, data)
|
||||
{
|
||||
radio_value_t value;
|
||||
char buf[10];
|
||||
const char *newptr;
|
||||
PROCESS_BEGIN();
|
||||
|
||||
value = shell_strtolong(data, &newptr);
|
||||
|
||||
/* If no channel was given on the command line, we print out the
|
||||
current channel. */
|
||||
if(newptr == data) {
|
||||
if(get_param(RADIO_PARAM_CHANNEL, &value) == RADIO_RESULT_OK) {
|
||||
|
||||
}
|
||||
} else {
|
||||
set_param(RADIO_PARAM_CHANNEL, value);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", value);
|
||||
shell_output_str(&rfchannel_command, "Channel: ", buf);
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(shell_ccathresholds_process, ev, data)
|
||||
{
|
||||
radio_value_t value;
|
||||
char buf[10];
|
||||
const char *newptr;
|
||||
PROCESS_BEGIN();
|
||||
|
||||
value = shell_strtolong(data, &newptr);
|
||||
|
||||
/* If no channel was given on the command line, we print out the
|
||||
current channel. */
|
||||
if(newptr == data) {
|
||||
if(get_param(RADIO_PARAM_CCA_THRESHOLD, &value) == RADIO_RESULT_OK) {
|
||||
|
||||
}
|
||||
} else {
|
||||
set_param(RADIO_PARAM_CCA_THRESHOLD, value);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d dBm", value);
|
||||
shell_output_str(&rfchannel_command, "CCA Threshold: ", buf);
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(shell_macconf_process, ev, data)
|
||||
{
|
||||
radio_value_t value;
|
||||
char buf[10];
|
||||
const char *newptr;
|
||||
PROCESS_BEGIN();
|
||||
|
||||
value = shell_strtolong(data, &newptr);
|
||||
|
||||
/* If no transmission power was given on the command line, we print
|
||||
out the current macconf. */
|
||||
if(newptr == data) {
|
||||
value = params_get_macconf();
|
||||
} else {
|
||||
params_set_macconf(value);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%3d", value);
|
||||
shell_output_str(&txpower_command, "macconf: ", buf);
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(shell_panid_process, ev, data)
|
||||
{
|
||||
radio_value_t value;
|
||||
char buf[10];
|
||||
char *newptr;
|
||||
PROCESS_BEGIN();
|
||||
|
||||
value = strtol(data, &newptr, 0);
|
||||
|
||||
/* If no channel was given on the command line, we print out the
|
||||
current channel. */
|
||||
if(newptr == data) {
|
||||
if(get_param(RADIO_PARAM_PAN_ID, &value) != RADIO_RESULT_OK) {
|
||||
// printf("error: get_param RADIO_PARAM_PAN_ID\n");
|
||||
}
|
||||
} else {
|
||||
set_param(RADIO_PARAM_PAN_ID, value);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf),"0x%02x%02x\n", (value >> 8) & 0xFF, value & 0xFF);
|
||||
shell_output_str(&panid_command, "panid: ", buf);
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(shell_saverfparam_process, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
/* Save txpower */
|
||||
params_save_txpower();
|
||||
/* Save rfchannel */
|
||||
params_save_channel();
|
||||
/* Save ccathresholds */
|
||||
// todo
|
||||
|
||||
/* Save panid */
|
||||
params_save_panid();
|
||||
/* Save macconf */
|
||||
params_save_macconf();
|
||||
|
||||
shell_output_str(&rfchannel_command, "saverfparam done ", 0);
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
shell_merkur_init(void)
|
||||
{
|
||||
// shell_ps_init();
|
||||
shell_reboot_init();
|
||||
shell_register_command(&txpower_command);
|
||||
shell_register_command(&rfchannel_command);
|
||||
shell_register_command(&ccathresholds_command);
|
||||
shell_register_command(&panid_command);
|
||||
shell_register_command(&macconf_command);
|
||||
shell_register_command(&saverfparam_command);
|
||||
// shell_register_command(&s_command);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Header file for Tmote Sky-specific Contiki shell commands
|
||||
* \author
|
||||
* harald pichler <harald@the-develop.net>
|
||||
*/
|
||||
|
||||
#ifndef SHELL_MERKUR_H_
|
||||
#define SHELL_MERKUR_H_
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
void shell_merkur_init(void);
|
||||
|
||||
#endif /* SHELL_MERKUR_H_ */
|
|
@ -1,2 +0,0 @@
|
|||
time_src = time.c resource_gmtime.c resource_timestamp.c \
|
||||
resource_timezone.c resource_crontab.c cron.c
|
|
@ -1,20 +0,0 @@
|
|||
Timezones
|
||||
=========
|
||||
|
||||
The new version supports time zones and daylight saving time (DST).
|
||||
Currently we support only a single timezone. We use the UNIX timezone
|
||||
format which is usually specified in an environment variable TZ.
|
||||
|
||||
Note that for timezone information you can have different
|
||||
representation, either relative to Universal Time Coordinated (UTC) or
|
||||
to International Atomic Time (TAI), the latter contains leap seconds.
|
||||
Since most systems today use UTC *and* the clock of a microcontroller
|
||||
is typically not accurate enough to care about leap seconds, we're using
|
||||
timezone files relative to UTC.
|
||||
|
||||
Wikipedia has a very good treatment of the public timezone database in
|
||||
https://en.wikipedia.org/wiki/Tz_database
|
||||
|
||||
The format of timezone strings is described in the Linux manual page
|
||||
tzset(3). The timezone specification for Europe/Vienna is
|
||||
CET-1CEST,M3.5.0,M10.5.0/3
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1989 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Paul Vixie.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted
|
||||
* provided that the above copyright notice and this paragraph are
|
||||
* duplicated in all such forms and that any documentation,
|
||||
* advertising materials, and other materials related to such
|
||||
* distribution and use acknowledge that the software was developed
|
||||
* by the University of California, Berkeley. The name of the
|
||||
* University may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* @(#)bitstring.h 5.2 (Berkeley) 4/4/90
|
||||
*/
|
||||
|
||||
typedef unsigned char bitstr_t;
|
||||
|
||||
/* internal macros */
|
||||
/* byte of the bitstring bit is in */
|
||||
#define _bit_byte(bit) \
|
||||
((bit) >> 3)
|
||||
|
||||
/* mask for the bit within its byte */
|
||||
#define _bit_mask(bit) \
|
||||
(1 << ((bit)&0x7))
|
||||
|
||||
/* external macros */
|
||||
/* bytes in a bitstring of nbits bits */
|
||||
#define bitstr_size(nbits) \
|
||||
((((nbits) - 1) >> 3) + 1)
|
||||
|
||||
|
||||
/* allocate a bitstring on the stack */
|
||||
#define bit_decl(name, nbits) \
|
||||
(name)[bitstr_size(nbits)]
|
||||
|
||||
/* is bit N of bitstring name set? */
|
||||
#define bit_test(name, bit) \
|
||||
((name)[_bit_byte(bit)] & _bit_mask(bit))
|
||||
|
||||
/* set bit N of bitstring name */
|
||||
#define bit_set(name, bit) \
|
||||
(name)[_bit_byte(bit)] |= _bit_mask(bit)
|
||||
|
||||
/* clear bit N of bitstring name */
|
||||
#define bit_clear(name, bit) \
|
||||
(name)[_bit_byte(bit)] &= ~_bit_mask(bit)
|
||||
|
||||
/* clear bits start ... stop in bitstring */
|
||||
#define bit_nclear(name, start, stop) { \
|
||||
register bitstr_t *_name = name; \
|
||||
register int _start = start, _stop = stop; \
|
||||
register int _startbyte = _bit_byte(_start); \
|
||||
register int _stopbyte = _bit_byte(_stop); \
|
||||
if (_startbyte == _stopbyte) { \
|
||||
_name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \
|
||||
(0xff << ((_stop&0x7) + 1))); \
|
||||
} else { \
|
||||
_name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \
|
||||
while (++_startbyte < _stopbyte) \
|
||||
_name[_startbyte] = 0; \
|
||||
_name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* set bits start ... stop in bitstring */
|
||||
#define bit_nset(name, start, stop) { \
|
||||
register bitstr_t *_name = name; \
|
||||
register int _start = start, _stop = stop; \
|
||||
register int _startbyte = _bit_byte(_start); \
|
||||
register int _stopbyte = _bit_byte(_stop); \
|
||||
if (_startbyte == _stopbyte) { \
|
||||
_name[_startbyte] |= ((0xff << (_start&0x7)) & \
|
||||
(0xff >> (7 - (_stop&0x7)))); \
|
||||
} else { \
|
||||
_name[_startbyte] |= 0xff << ((_start)&0x7); \
|
||||
while (++_startbyte < _stopbyte) \
|
||||
_name[_startbyte] = 0xff; \
|
||||
_name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* find first bit clear in name */
|
||||
#define bit_ffc(name, nbits, value) { \
|
||||
register bitstr_t *_name = name; \
|
||||
register int _byte, _nbits = nbits; \
|
||||
register int _stopbyte = _bit_byte(_nbits), _value = -1; \
|
||||
for (_byte = 0; _byte <= _stopbyte; ++_byte) \
|
||||
if (_name[_byte] != 0xff) { \
|
||||
_value = _byte << 3; \
|
||||
for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \
|
||||
++_value, _stopbyte >>= 1); \
|
||||
break; \
|
||||
} \
|
||||
*(value) = _value; \
|
||||
}
|
||||
|
||||
/* find first bit set in name */
|
||||
#define bit_ffs(name, nbits, value) { \
|
||||
register bitstr_t *_name = name; \
|
||||
register int _byte, _nbits = nbits; \
|
||||
register int _stopbyte = _bit_byte(_nbits), _value = -1; \
|
||||
for (_byte = 0; _byte <= _stopbyte; ++_byte) \
|
||||
if (_name[_byte]) { \
|
||||
_value = _byte << 3; \
|
||||
for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \
|
||||
++_value, _stopbyte >>= 1); \
|
||||
break; \
|
||||
} \
|
||||
*(value) = _value; \
|
||||
}
|
488
apps/time/cron.c
488
apps/time/cron.c
|
@ -1,488 +0,0 @@
|
|||
/**
|
||||
* \file
|
||||
* cron: Cron-like functionality
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*
|
||||
* \brief cron-like command scheduler
|
||||
*
|
||||
* Inspired by vixie's cron by Paul Vixie which is
|
||||
* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
*
|
||||
* Distribute freely, except: don't remove my name from the source or
|
||||
* documentation (don't take credit for my work), mark your changes (don't
|
||||
* get me blamed for your possible bugs), don't alter or remove this
|
||||
* notice. May be sold if buildable source is provided to buyer. No
|
||||
* warrantee of any kind, express or implied, is included with this
|
||||
* software; use at your own risk, responsibility for damages (if any) to
|
||||
* anyone resulting from the use of this software rests entirely with the
|
||||
* user.
|
||||
*
|
||||
* Changes to make this work on a microcontroller by Ralf Schlatterbeck
|
||||
* In fact this is mostly a rewrite but keeps central algorithms and
|
||||
* some data structures of the original.
|
||||
* The syntax is simplified, we don't support the @ notation (e.g.
|
||||
* @hourly) and named entities (e.g. weekday names instead of numbers).
|
||||
* Furthermore we can't send email and don't support environment
|
||||
* variables. The called commands are functions registered via a
|
||||
* registration mechanism before runtime.
|
||||
* Copyright 2016 Ralf Schlatterbeck, distribute with the conditions
|
||||
* given above.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include "contiki.h"
|
||||
#include "cron.h"
|
||||
#include "xtime.h"
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
static struct cron_entry cron_entries [MAX_CRON_ENTRIES];
|
||||
static struct cron_cmd cron_commands [MAX_CRON_COMMANDS];
|
||||
static size_t cron_registered_entries = 0;
|
||||
static size_t cron_registered_commands = 0;
|
||||
static struct cron_entry *entry_freelist = NULL;
|
||||
static struct cron_entry *entry_list = NULL;
|
||||
|
||||
typedef int64_t minute_t;
|
||||
static xtime_t start_time;
|
||||
static minute_t cron_clock_time;
|
||||
|
||||
/* Register a new cron command
|
||||
* A command consists of a name (which must be unique, uniqueness is not
|
||||
* enforced currently as registrations are done once at initialization
|
||||
* time), a function to be called and a parameter.
|
||||
*/
|
||||
int cron_register_command
|
||||
(const char *name, void (*function)(void *), void * parameter)
|
||||
{
|
||||
if (cron_registered_commands >= MAX_CRON_COMMANDS) {
|
||||
return -1;
|
||||
}
|
||||
cron_commands [cron_registered_commands].name = name;
|
||||
cron_commands [cron_registered_commands].function = function;
|
||||
cron_commands [cron_registered_commands].parameter = parameter;
|
||||
cron_registered_commands++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new crontab entry.
|
||||
* This allocates from the freelist and returns NULL if no more entries
|
||||
* are available.
|
||||
* Implementation note: If cron_registered_entries is 0 we first
|
||||
* initialize the entry_freelist and the entry_list.
|
||||
*/
|
||||
struct cron_entry *allocate_cron_entry (void)
|
||||
{
|
||||
size_t n;
|
||||
struct cron_entry *e;
|
||||
if (cron_registered_entries == 0) {
|
||||
entry_list = NULL;
|
||||
entry_freelist = &cron_entries [0];
|
||||
for (n=0; n < (MAX_CRON_ENTRIES - 1); n++) {
|
||||
cron_entries [n].next = &cron_entries [n+1];
|
||||
}
|
||||
cron_entries [MAX_CRON_ENTRIES - 1].next = NULL;
|
||||
}
|
||||
if (cron_registered_entries >= MAX_CRON_ENTRIES) {
|
||||
return NULL;
|
||||
}
|
||||
e = entry_freelist;
|
||||
entry_freelist = e->next;
|
||||
e->next = entry_list;
|
||||
entry_list = e;
|
||||
cron_registered_entries++;
|
||||
return e;
|
||||
}
|
||||
|
||||
void free_cron_entry (struct cron_entry *obsolete)
|
||||
{
|
||||
struct cron_entry *e;
|
||||
assert (cron_registered_entries);
|
||||
if (entry_list == obsolete) {
|
||||
entry_list = obsolete->next;
|
||||
obsolete->next = entry_freelist;
|
||||
entry_freelist = obsolete;
|
||||
cron_registered_entries--;
|
||||
return;
|
||||
}
|
||||
for (e=entry_list; e; e=e->next) {
|
||||
if (e->next == obsolete) {
|
||||
e->next = obsolete->next;
|
||||
obsolete->next = entry_freelist;
|
||||
entry_freelist = obsolete;
|
||||
cron_registered_entries--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert (e != NULL);
|
||||
}
|
||||
|
||||
struct cron_entry *get_cron_entry (size_t idx)
|
||||
{
|
||||
if (idx >= MAX_CRON_ENTRIES) {
|
||||
return NULL;
|
||||
}
|
||||
return &cron_entries [idx];
|
||||
}
|
||||
|
||||
/* Set the number in bits, return 0 on success -1 on error */
|
||||
static int set_element (bitstr_t *bits, int low, int high, int n)
|
||||
{
|
||||
if (n < low || n > high) {
|
||||
return -1;
|
||||
}
|
||||
bit_set (bits, (n - low));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *get_number (int *np, int high, const char *s)
|
||||
{
|
||||
char *endptr;
|
||||
long l = strtol (s, &endptr, 10);
|
||||
if (endptr == s || errno == ERANGE || l > high) {
|
||||
return NULL;
|
||||
}
|
||||
*np = l;
|
||||
return endptr;
|
||||
}
|
||||
|
||||
static const char *get_range (bitstr_t *bits, int low, int high, const char *s)
|
||||
{
|
||||
int i;
|
||||
int n1, n2, n3;
|
||||
|
||||
if (*s == '*') {
|
||||
/* '*' means "first-last" but can be modified by /step */
|
||||
n1 = low;
|
||||
n2 = high;
|
||||
if (*++s == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
s = get_number (&n1, high, s);
|
||||
if (s == NULL || *s == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
if (*s != '-') {
|
||||
if (set_element (bits, low, high, n1) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return s;
|
||||
} else {
|
||||
if (*++s == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
s = get_number (&n2, high, s);
|
||||
if (*s == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*s == '/') {
|
||||
if (*++s == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
s = get_number (&n3, high, s);
|
||||
if (*s == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
n3 = 1;
|
||||
}
|
||||
/* Explicit check for sane values */
|
||||
if (n1 < low || n1 > high || n2 < low || n2 > high) {
|
||||
return NULL;
|
||||
}
|
||||
for (i=n1; i<=n2; i+=n3) {
|
||||
if (set_element (bits, low, high, i) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static const char *get_list (bitstr_t *bits, int low, int high, const char *s)
|
||||
{
|
||||
int done = 0;
|
||||
bit_nclear (bits, 0, (high - low + 1));
|
||||
while (!done) {
|
||||
s = get_range (bits, low, high, s);
|
||||
if (NULL == s) {
|
||||
return NULL;
|
||||
}
|
||||
if (*s == ',') {
|
||||
s++;
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
/* Skip white space */
|
||||
while (s && isspace (*s)) {
|
||||
s++;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a single crontab entry on a single line.
|
||||
* We get the line via CoAP.
|
||||
* Returns 0 if parsed successfully, -1 on error.
|
||||
* On error the err pointer is set to the error message.
|
||||
*/
|
||||
int parse_crontab_line
|
||||
(const char *line, struct cron_entry *e, const char **err)
|
||||
{
|
||||
size_t n;
|
||||
const char *s = line;
|
||||
size_t cmd_len = 0;
|
||||
|
||||
e->flags &= ~VALID;
|
||||
if (*s == '*') {
|
||||
e->flags |= MIN_STAR;
|
||||
}
|
||||
s = get_list (e->minute, FIRST_MINUTE, LAST_MINUTE, s);
|
||||
if (NULL == s || *s == '\0') {
|
||||
*err = "minute";
|
||||
return -1;
|
||||
}
|
||||
if (*s == '*') {
|
||||
e->flags |= HR_STAR;
|
||||
}
|
||||
s = get_list (e->hour, FIRST_HOUR, LAST_HOUR, s);
|
||||
if (NULL == s || *s == '\0') {
|
||||
*err = "hour";
|
||||
return -1;
|
||||
}
|
||||
if (*s == '*') {
|
||||
e->flags |= DOM_STAR;
|
||||
}
|
||||
s = get_list (e->dom, FIRST_DOM, LAST_DOM, s);
|
||||
if (NULL == s || *s == '\0') {
|
||||
*err = "dom";
|
||||
return -1;
|
||||
}
|
||||
s = get_list (e->month, FIRST_MONTH, LAST_MONTH, s);
|
||||
if (NULL == s || *s == '\0') {
|
||||
*err = "month";
|
||||
return -1;
|
||||
}
|
||||
if (*s == '*') {
|
||||
e->flags |= DOW_STAR;
|
||||
}
|
||||
s = get_list (e->dow, FIRST_DOW, LAST_DOW, s);
|
||||
if (NULL == s || *s == '\0') {
|
||||
*err = "dow";
|
||||
return -1;
|
||||
}
|
||||
/* Make sundays equivalent */
|
||||
if (bit_test (e->dow, 0) || bit_test (e->dow, 7)) {
|
||||
bit_set (e->dow, 0);
|
||||
bit_set (e->dow, 7);
|
||||
}
|
||||
/* strip whitespace at *end* of command
|
||||
* by getting length without whitespace
|
||||
*/
|
||||
for (n=0; s [n]; n++) {
|
||||
if (!isspace (s [n])) {
|
||||
cmd_len = n + 1;
|
||||
}
|
||||
}
|
||||
for (n=0; n<cron_registered_commands; n++) {
|
||||
if ( cmd_len == strlen (cron_commands [n].name)
|
||||
&& !strncmp (cron_commands [n].name, s, cmd_len)
|
||||
)
|
||||
{
|
||||
e->cmd = &cron_commands [n];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n == cron_registered_commands) {
|
||||
*err = "command";
|
||||
return -1;
|
||||
}
|
||||
e->flags |= VALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_time (void)
|
||||
{
|
||||
struct xtm *tm;
|
||||
struct xtimeval tv;
|
||||
xgettimeofday (&tv, NULL);
|
||||
start_time = tv.tv_sec;
|
||||
tm = xlocaltime (&start_time);
|
||||
/* We adjust the time to GMT so we can catch DST changes */
|
||||
cron_clock_time = (start_time + tm->tm_gmtoff) / (xtime_t)SECONDS_PER_MINUTE;
|
||||
}
|
||||
|
||||
static void find_jobs (minute_t vtime, int do_wild, int do_nonwild)
|
||||
{
|
||||
xtime_t virtual_second = vtime * SECONDS_PER_MINUTE;
|
||||
struct xtm *tm = xgmtime (&virtual_second);
|
||||
int minute, hour, dom, month, dow;
|
||||
struct cron_entry *e;
|
||||
|
||||
/* make 0-based values out of these so we can use them as indicies */
|
||||
minute = tm->tm_min -FIRST_MINUTE;
|
||||
hour = tm->tm_hour -FIRST_HOUR;
|
||||
dom = tm->tm_mday -FIRST_DOM;
|
||||
month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
|
||||
dow = tm->tm_wday -FIRST_DOW;
|
||||
#ifdef DEBUG
|
||||
printf ("%d %d %d %d %d\n", minute, hour, dom, month, dow);
|
||||
#endif
|
||||
|
||||
/* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
|
||||
* first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
|
||||
* on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
|
||||
* is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre.
|
||||
* like many bizarre things, it's the standard.
|
||||
*/
|
||||
for (e = entry_list; e; e = e->next) {
|
||||
#ifdef DEBUG
|
||||
if (e->flags & VALID) {
|
||||
printf ("Checking entry %s\n", e->cmd->name);
|
||||
}
|
||||
printf ("valid: %d\n", (e->flags & VALID));
|
||||
printf ("minute: %d\n", (bit_test (e->minute, minute)));
|
||||
printf ("hour: %d\n", (bit_test (e->hour, hour)));
|
||||
printf ("month %d\n", (bit_test (e->month, month)));
|
||||
printf ("dom* %d\n", (e->flags & DOM_STAR));
|
||||
printf ("dow* %d\n", (e->flags & DOW_STAR));
|
||||
printf ("dow %d\n", (bit_test (e->dow, dow)));
|
||||
printf ("dom %d\n", (bit_test (e->dom, dom)));
|
||||
printf ("min* %d\n", (e->flags & MIN_STAR));
|
||||
printf ("hr* %d\n", (e->flags & HR_STAR));
|
||||
printf ("nonwild %d\n", (do_nonwild));
|
||||
#endif
|
||||
if ( (e->flags & VALID)
|
||||
&& bit_test (e->minute, minute)
|
||||
&& bit_test (e->hour, hour)
|
||||
&& bit_test (e->month, month)
|
||||
&& ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
|
||||
? (bit_test (e->dow, dow) && bit_test (e->dom, dom))
|
||||
: (bit_test (e->dow, dow) || bit_test (e->dom, dom))
|
||||
)
|
||||
)
|
||||
{
|
||||
if ( (do_nonwild && !(e->flags & (MIN_STAR | HR_STAR)))
|
||||
|| (do_wild && (e->flags & (MIN_STAR | HR_STAR)))
|
||||
)
|
||||
{
|
||||
printf ("Cron: calling \"%s\"\n", e->cmd->name);
|
||||
e->cmd->function (e->cmd->parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The cron callback function must be run regularly, at least once per
|
||||
* minute.
|
||||
* Implementation:
|
||||
* Clocks are in minutes since the epoch (time() / 60).
|
||||
* virtual_time is the time it *would* be if we are called promptly and
|
||||
* nobody ever changed the clock. It is monotonically increasing...
|
||||
* unless a timejump happens.
|
||||
* time_running is the time we were last called. We determine
|
||||
* initialization by checking time_running for -1.
|
||||
* cron_clock_time is the current time for this run.
|
||||
*/
|
||||
void cron (void)
|
||||
{
|
||||
static minute_t time_running = -1;
|
||||
static minute_t virtual_time = -1;
|
||||
minute_t time_diff;
|
||||
|
||||
/*
|
||||
* ... calculate how the current time differs from
|
||||
* our virtual clock. Classify the change into one
|
||||
* of 4 cases
|
||||
*/
|
||||
set_time ();
|
||||
if (time_running == cron_clock_time) {
|
||||
#ifdef DEBUG
|
||||
printf ("time not reached\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
time_running = cron_clock_time;
|
||||
time_diff = time_running - virtual_time;
|
||||
#ifdef DEBUG
|
||||
printf ("time_diff: %ld\n", (long)time_diff);
|
||||
#endif
|
||||
/* shortcut for the most common case */
|
||||
if (time_diff == 1) {
|
||||
virtual_time = time_running;
|
||||
find_jobs (virtual_time, 1, 1);
|
||||
} else {
|
||||
int wakeup_kind = -1;
|
||||
if (time_diff > -(3*MINUTE_COUNT)) {
|
||||
wakeup_kind = 0;
|
||||
}
|
||||
if (time_diff > 0) {
|
||||
wakeup_kind = 1;
|
||||
}
|
||||
if (time_diff > 5) {
|
||||
wakeup_kind = 2;
|
||||
}
|
||||
if (time_diff > (3*MINUTE_COUNT)) {
|
||||
wakeup_kind = 3;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf ("wakeup_kind: %d\n", wakeup_kind);
|
||||
#endif
|
||||
switch (wakeup_kind) {
|
||||
/* time_diff is a small positive number (wokeup late)
|
||||
* run jobs for each virtual minute until caught up.
|
||||
*/
|
||||
case 1:
|
||||
do {
|
||||
virtual_time++;
|
||||
find_jobs (virtual_time, 1, 1);
|
||||
} while (virtual_time < time_running);
|
||||
break;
|
||||
/* time_diff is a medium-sized positive number, for example
|
||||
* because we went to DST. Run wildcard jobs once, then run any
|
||||
* fixed-time jobs that would otherwise be skipped. If we use up
|
||||
* our minute (possible, if there are a lot of jobs to run) go
|
||||
* around the loop again so that wildcard jobs have a chance to
|
||||
* run, and we do our housekeeping.
|
||||
*/
|
||||
case 2:
|
||||
/* run wildcard jobs for current minute */
|
||||
find_jobs (time_running, 1, 0);
|
||||
/* run fixed-time jobs for each minute missed */
|
||||
do {
|
||||
virtual_time++;
|
||||
find_jobs (virtual_time, 0, 1);
|
||||
set_time ();
|
||||
} while ( virtual_time < time_running
|
||||
&& cron_clock_time == time_running
|
||||
);
|
||||
break;
|
||||
/* time_diff is a small or medium-sized negative num, eg.
|
||||
* because of DST ending. Just run the wildcard jobs. The
|
||||
* fixed-time jobs probably have already run, and should not be
|
||||
* repeated. virtual_time does not change until we are caught up.
|
||||
*/
|
||||
case 0:
|
||||
find_jobs (time_running, 1, 0);
|
||||
break;
|
||||
/* Other: time has changed a *lot*, jump virtual time, and run
|
||||
* everything
|
||||
*/
|
||||
default:
|
||||
virtual_time = time_running;
|
||||
find_jobs (time_running, 1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Definitions for cron
|
||||
* Inspired by vixie's cron by Paul Vixie which is
|
||||
* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
*
|
||||
* Distribute freely, except: don't remove my name from the source or
|
||||
* documentation (don't take credit for my work), mark your changes (don't
|
||||
* get me blamed for your possible bugs), don't alter or remove this
|
||||
* notice. May be sold if buildable source is provided to buyer. No
|
||||
* warrantee of any kind, express or implied, is included with this
|
||||
* software; use at your own risk, responsibility for damages (if any) to
|
||||
* anyone resulting from the use of this software rests entirely with the
|
||||
* user.
|
||||
* Changes to make this work on a microcontroller by Ralf Schlatterbeck
|
||||
* In fact this is mostly a rewrite but keeps central algorithms of the
|
||||
* original.
|
||||
* Copyright 2016 Ralf Schlatterbeck, distribute with the conditions
|
||||
* given above.
|
||||
*/
|
||||
|
||||
#ifndef _cron_h_
|
||||
#define _cron_h_
|
||||
|
||||
#include "bitstring.h"
|
||||
|
||||
#define SECONDS_PER_MINUTE 60
|
||||
|
||||
#define FIRST_MINUTE 0
|
||||
#define LAST_MINUTE 59
|
||||
#define MINUTE_COUNT (LAST_MINUTE - FIRST_MINUTE + 1)
|
||||
|
||||
#define FIRST_HOUR 0
|
||||
#define LAST_HOUR 23
|
||||
#define HOUR_COUNT (LAST_HOUR - FIRST_HOUR + 1)
|
||||
|
||||
#define FIRST_DOM 1
|
||||
#define LAST_DOM 31
|
||||
#define DOM_COUNT (LAST_DOM - FIRST_DOM + 1)
|
||||
|
||||
#define FIRST_MONTH 1
|
||||
#define LAST_MONTH 12
|
||||
#define MONTH_COUNT (LAST_MONTH - FIRST_MONTH + 1)
|
||||
|
||||
/* note on DOW: 0 and 7 are both Sunday, for compatibility reasons. */
|
||||
#define FIRST_DOW 0
|
||||
#define LAST_DOW 7
|
||||
#define DOW_COUNT (LAST_DOW - FIRST_DOW + 1)
|
||||
|
||||
#ifndef MAX_CRON_ENTRIES
|
||||
#define MAX_CRON_ENTRIES 5
|
||||
#endif
|
||||
|
||||
#ifndef MAX_CRON_COMMANDS
|
||||
#define MAX_CRON_COMMANDS 5
|
||||
#endif
|
||||
|
||||
struct cron_cmd {
|
||||
const char *name;
|
||||
void (*function)(void *);
|
||||
void *parameter;
|
||||
};
|
||||
|
||||
struct cron_entry {
|
||||
struct cron_entry *next;
|
||||
struct cron_cmd *cmd;
|
||||
bitstr_t bit_decl(minute, MINUTE_COUNT);
|
||||
bitstr_t bit_decl(hour, HOUR_COUNT);
|
||||
bitstr_t bit_decl(dom, DOM_COUNT);
|
||||
bitstr_t bit_decl(month, MONTH_COUNT);
|
||||
bitstr_t bit_decl(dow, DOW_COUNT);
|
||||
int flags;
|
||||
|
||||
#define DOM_STAR 0x01
|
||||
#define DOW_STAR 0x02
|
||||
#define WHEN_REBOOT 0x04
|
||||
#define MIN_STAR 0x08
|
||||
#define HR_STAR 0x10
|
||||
#define VALID 0x20
|
||||
};
|
||||
|
||||
extern int parse_crontab_line
|
||||
(const char *line, struct cron_entry *e, const char **err);
|
||||
extern int cron_register_command
|
||||
(const char *name, void (*function)(void *), void * parameter);
|
||||
|
||||
extern struct cron_entry *allocate_cron_entry (void);
|
||||
extern struct cron_entry *get_cron_entry (size_t idx);
|
||||
extern void free_cron_entry (struct cron_entry *e);
|
||||
extern void cron (void);
|
||||
|
||||
#endif /* _cron_h_ */
|
|
@ -1,125 +0,0 @@
|
|||
/**
|
||||
* \file
|
||||
* Resource for crontab entry
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*
|
||||
* \brief get/put crontab entry
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "contiki.h"
|
||||
#include "time_resource.h"
|
||||
#include "jsonparse.h"
|
||||
#include "er-coap.h"
|
||||
#include "generic_resource.h"
|
||||
#include "cron.h"
|
||||
|
||||
static size_t get_index_from_uri (const char *uri)
|
||||
{
|
||||
const char *s;
|
||||
char *endptr;
|
||||
size_t idx;
|
||||
if (uri == NULL) {
|
||||
return MAX_CRON_ENTRIES;
|
||||
}
|
||||
if (NULL == (s = strrchr (uri, '/'))) {
|
||||
return MAX_CRON_ENTRIES;
|
||||
}
|
||||
idx = strtoul (s+1, &endptr, 10);
|
||||
if (s == endptr || *endptr != '\0') {
|
||||
return MAX_CRON_ENTRIES;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
int crontab_from_string
|
||||
(const char *name, const char *uri, const char *query, const char *s)
|
||||
{
|
||||
const char *err;
|
||||
int res;
|
||||
size_t idx = get_index_from_uri (uri);
|
||||
if (idx >= MAX_CRON_ENTRIES) {
|
||||
return -1;
|
||||
}
|
||||
res = parse_crontab_line (s, get_cron_entry (idx), &err);
|
||||
if (res < 0) {
|
||||
printf ("Error parsing: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
crontab_to_string
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
/* FIXME: For now we only return "valid" or "invalid" until someone
|
||||
* comes up with a clever algorithm to reconstruct a crontab string
|
||||
* from the cron_entry struct.
|
||||
*/
|
||||
size_t idx = get_index_from_uri (uri);
|
||||
struct cron_entry *e;
|
||||
if (idx >= MAX_CRON_ENTRIES) {
|
||||
return MAX_GET_STRING_LENGTH;
|
||||
}
|
||||
e = get_cron_entry (idx);
|
||||
if (e->flags & VALID) {
|
||||
return snprintf (buf, bsize, "valid");
|
||||
}
|
||||
return snprintf (buf, bsize, "invalid");
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( crontab
|
||||
, crontab-entry
|
||||
, s
|
||||
, 1
|
||||
, crontab_from_string
|
||||
, crontab_to_string
|
||||
);
|
||||
|
||||
/* Allocate all cron entries and the necessary resources */
|
||||
void activate_cron_resources (void)
|
||||
{
|
||||
size_t n;
|
||||
for (n=0; n<MAX_CRON_ENTRIES; n++) {
|
||||
resource_t *res;
|
||||
char *buf;
|
||||
size_t len;
|
||||
struct cron_entry *e;
|
||||
char name [15];
|
||||
/* Need to copy the resource because resource->url holds the path
|
||||
* under which we activate it using rest_activate_resource
|
||||
*/
|
||||
if (NULL == (res = malloc (sizeof (*res)))) {
|
||||
printf ("Error malloc\n");
|
||||
break;
|
||||
}
|
||||
memcpy (res, &res_crontab, sizeof (*res));
|
||||
e = allocate_cron_entry ();
|
||||
assert (!(e->flags & VALID));
|
||||
len = snprintf (name, sizeof (name), "crontab/%u", n);
|
||||
name [sizeof (name) -1] = '\0';
|
||||
assert (len < 15);
|
||||
if (NULL == (buf = malloc (len + 1))) {
|
||||
printf ("Error malloc\n");
|
||||
break;
|
||||
}
|
||||
strcpy (buf, name);
|
||||
rest_activate_resource (res, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* VI settings, see coding style
|
||||
* ex:ts=8:et:sw=2
|
||||
*/
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/**
|
||||
* \file
|
||||
* Resource for gmtime (utc) / localtime handling
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*
|
||||
* \brief get time as a string in utc or localtime
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "contiki.h"
|
||||
#include "xtime.h"
|
||||
#include "time_resource.h"
|
||||
#include "jsonparse.h"
|
||||
#include "er-coap.h"
|
||||
#include "generic_resource.h"
|
||||
|
||||
size_t time_to_string
|
||||
(const char *name, const char *uri, const char *query, char *buf, size_t bs)
|
||||
{
|
||||
struct xtimeval tv;
|
||||
struct xtm tm;
|
||||
struct xtm *(*method)(const xtime_t *, struct xtm *) = xgmtime_r;
|
||||
if (0 == strcmp (name, "localtime")) {
|
||||
method = xlocaltime_r;
|
||||
}
|
||||
xgettimeofday (&tv, NULL);
|
||||
method (&tv.tv_sec, &tm);
|
||||
return snprintf
|
||||
( buf
|
||||
, bs
|
||||
, "%lu-%02u-%02u %02u:%02u:%02u %s"
|
||||
, 1900 + tm.tm_year
|
||||
, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec
|
||||
, tm.tm_zone
|
||||
);
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE \
|
||||
( localtime
|
||||
, Local time
|
||||
, formatted time
|
||||
, 1
|
||||
, NULL
|
||||
, time_to_string
|
||||
);
|
||||
|
||||
GENERIC_RESOURCE \
|
||||
( utc
|
||||
, UTC
|
||||
, formatted time
|
||||
, 1
|
||||
, NULL
|
||||
, time_to_string
|
||||
);
|
||||
|
||||
/*
|
||||
* VI settings, see coding style
|
||||
* ex:ts=8:et:sw=2
|
||||
*/
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/**
|
||||
* \file
|
||||
* Resource for timestamp handling
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*
|
||||
* \brief get/put time in seconds since 1970 (UNIX time)
|
||||
* Note: the internal format of the time in seconds is a 64bit number
|
||||
* unfortunately javascript (json) will only support double for which
|
||||
* the mantissa isn't long enough for representing that number. So we're
|
||||
* back to 32 bit and have a year 2038 problem.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "contiki.h"
|
||||
#include "xtime.h"
|
||||
#include "time_resource.h"
|
||||
#include "jsonparse.h"
|
||||
#include "er-coap.h"
|
||||
#include "generic_resource.h"
|
||||
|
||||
int timestamp_from_string
|
||||
(const char *name, const char *uri, const char *query, const char *s)
|
||||
{
|
||||
struct xtimeval tv;
|
||||
// FIXME: Platform has no strtoll (long long)?
|
||||
tv.tv_sec = strtol (s, NULL, 10);
|
||||
xsettimeofday (&tv, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
timestamp_to_string
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
struct xtimeval tv;
|
||||
xgettimeofday (&tv, NULL);
|
||||
// FIXME: Platform doesn't seem to support long long printing
|
||||
// We get empty string
|
||||
return snprintf (buf, bsize, "%ld", (long)tv.tv_sec);
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( timestamp
|
||||
, Time
|
||||
, s
|
||||
, 1
|
||||
, timestamp_from_string
|
||||
, timestamp_to_string
|
||||
);
|
||||
|
||||
/*
|
||||
* VI settings, see coding style
|
||||
* ex:ts=8:et:sw=2
|
||||
*/
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/**
|
||||
* \file
|
||||
* Resource for timezone handling
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@runtux.com>
|
||||
*
|
||||
* \brief get/put timezone string
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "contiki.h"
|
||||
#include "xtime.h"
|
||||
#include "time_resource.h"
|
||||
#include "jsonparse.h"
|
||||
#include "er-coap.h"
|
||||
#include "generic_resource.h"
|
||||
|
||||
int timezone_from_string
|
||||
(const char *name, const char *uri, const char *query, const char *s)
|
||||
{
|
||||
set_tz (s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
timezone_to_string
|
||||
( const char *name
|
||||
, const char *uri
|
||||
, const char *query
|
||||
, char *buf
|
||||
, size_t bsize
|
||||
)
|
||||
{
|
||||
if (get_tz (buf, bsize) == NULL) {
|
||||
*buf = '\0';
|
||||
}
|
||||
return strlen (buf);
|
||||
}
|
||||
|
||||
GENERIC_RESOURCE
|
||||
( timezone
|
||||
, TZ
|
||||
, s
|
||||
, 1
|
||||
, timezone_from_string
|
||||
, timezone_to_string
|
||||
);
|
||||
|
||||
/*
|
||||
* VI settings, see coding style
|
||||
* ex:ts=8:et:sw=2
|
||||
*/
|
||||
|
847
apps/time/time.c
847
apps/time/time.c
|
@ -1,847 +0,0 @@
|
|||
/**
|
||||
* \addgroup Time related functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#include "contiki.h"
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "contiki-lib.h"
|
||||
#include "xtime.h"
|
||||
#include "tzparse.h"
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
|
||||
#define MONSPERYEAR 12
|
||||
|
||||
static const int mon_lengths[2][MONSPERYEAR] =
|
||||
{ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Static timezone information
|
||||
*/
|
||||
static struct tzoffset_info localtime_tzoffset;
|
||||
|
||||
/* Used for gmtime and localtime, according to manpage on linux the
|
||||
* internal value may be overwritten "by subsequent calls to any of the
|
||||
* date and time functions".
|
||||
*/
|
||||
static struct xtm tm;
|
||||
|
||||
/*
|
||||
* Internal variables to manage offset of utc from the contiki clock
|
||||
* and timezone offset from utc in minutes.
|
||||
* For now we don't manage the sub-second offset -- time of setting the
|
||||
* clock and the precisiont of the clock in use don't warrant this
|
||||
* effort.
|
||||
* The last_seconds is used to check if we had a seconds overflow,
|
||||
* although this happens only every 136 years :-)
|
||||
*/
|
||||
static xtime_t clock_offset;
|
||||
static uint32_t last_seconds;
|
||||
|
||||
static xtime_t
|
||||
transtime (xtime_t janfirst, int year, const struct tzrule *rp, long offset);
|
||||
|
||||
# define LEAP_YEAR(_year) \
|
||||
((_year % 4) == 0 && (_year % 100 != 0 || _year % 400 == 0))
|
||||
# define YDAYS(_year) (LEAP_YEAR(year) ? 366 : 365)
|
||||
|
||||
struct xtm *xgmtime_r (const xtime_t *timep, struct xtm *ptm)
|
||||
{
|
||||
unsigned int year;
|
||||
int days, month, month_len;
|
||||
xtime_t t = *timep;
|
||||
ptm->tm_sec = t % 60;
|
||||
t /= 60;
|
||||
ptm->tm_min = t % 60;
|
||||
t /= 60;
|
||||
ptm->tm_hour = t % 24;
|
||||
t /= 24;
|
||||
ptm->tm_wday = (t+4) % 7;
|
||||
year = 1970;
|
||||
days = 0;
|
||||
while ((days += YDAYS (year)) <= t)
|
||||
{
|
||||
year++;
|
||||
}
|
||||
ptm->tm_year = year - 1900;
|
||||
days -= YDAYS (year);
|
||||
t -= days;
|
||||
ptm->tm_yday = t;
|
||||
for (month=0; month<12; month++)
|
||||
{
|
||||
if (month == 1)
|
||||
{
|
||||
month_len = LEAP_YEAR (year) ? 29 : 28;
|
||||
}
|
||||
else
|
||||
{
|
||||
int m = month;
|
||||
if (m >= 7)
|
||||
{
|
||||
m -= 1;
|
||||
}
|
||||
m &= 1;
|
||||
month_len = m ? 30 : 31;
|
||||
}
|
||||
if (t >= month_len)
|
||||
{
|
||||
t -= month_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
ptm->tm_mon = month;
|
||||
ptm->tm_mday = t + 1;
|
||||
ptm->tm_isdst = 0;
|
||||
ptm->tm_gmtoff = 0;
|
||||
ptm->tm_zone = "UTC";
|
||||
return ptm;
|
||||
}
|
||||
|
||||
struct xtm *xgmtime (const xtime_t *timep)
|
||||
{
|
||||
return xgmtime_r (timep, &tm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute is_dst flag of given timestamp
|
||||
*/
|
||||
static int is_dst (const xtime_t *timep, const struct tzoffset_info *tzo)
|
||||
{
|
||||
xtime_t janfirst = 0;
|
||||
xtime_t starttime, endtime;
|
||||
int year = 1970;
|
||||
int lastdst = 0;
|
||||
if (tzo->dstname == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (year = 1970; janfirst < *timep; year++) {
|
||||
starttime = transtime (janfirst, year, &tzo->start, tzo->stdoffset);
|
||||
endtime = transtime (janfirst, year, &tzo->end, tzo->dstoffset);
|
||||
if (starttime <= *timep && endtime <= *timep) {
|
||||
lastdst = (starttime > endtime);
|
||||
} else if (starttime > *timep && endtime <= *timep) {
|
||||
return 0;
|
||||
} else if (starttime <= *timep && endtime > *timep) {
|
||||
return 1;
|
||||
} else if (starttime > *timep && endtime > *timep) {
|
||||
return lastdst;
|
||||
}
|
||||
janfirst += YDAYS (year) * SECSPERDAY;
|
||||
}
|
||||
return lastdst;
|
||||
}
|
||||
|
||||
struct xtm *xlocaltime_r (const xtime_t *timep, struct xtm *ptm)
|
||||
{
|
||||
const struct tzoffset_info *tzo = &localtime_tzoffset;
|
||||
int isdst = 0;
|
||||
long offset = 0;
|
||||
xtime_t t = *timep;
|
||||
|
||||
if (tzo->stdname == NULL) {
|
||||
set_tz (DEFAULT_TIMEZONE);
|
||||
}
|
||||
isdst = is_dst (timep, tzo);
|
||||
offset = isdst ? tzo->dstoffset : tzo->stdoffset;
|
||||
t -= offset;
|
||||
xgmtime_r (&t, ptm);
|
||||
ptm->tm_isdst = isdst;
|
||||
ptm->tm_gmtoff = -offset;
|
||||
ptm->tm_zone = isdst ? tzo->dstname : tzo->stdname;
|
||||
return ptm;
|
||||
}
|
||||
|
||||
struct xtm *xlocaltime (const xtime_t *timep)
|
||||
{
|
||||
return xlocaltime_r (timep, &tm);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get time in seconds and microseconds
|
||||
* xgettimeofday will return the clock time as the microseconds part
|
||||
* while xsettimeofday will *ignore* the microseconds part (for now).
|
||||
* Note that the contiki clock interface is broken anyway, we can't read
|
||||
* seconds and sub-seconds atomically. We try to work around this by
|
||||
* repeatedly reading seconds, sub-seconds, seconds until first and
|
||||
* second read of seconds match.
|
||||
*/
|
||||
int xgettimeofday (struct xtimeval *tv, struct timezone *tz)
|
||||
{
|
||||
uint32_t cs;
|
||||
if (tv) {
|
||||
int i;
|
||||
/* Limit tries to get the same second twice to two */
|
||||
for (i=0; i<2; i++) {
|
||||
cs = clock_seconds ();
|
||||
if (cs < last_seconds) {
|
||||
clock_offset += 0xFFFFFFFFL;
|
||||
clock_offset ++;
|
||||
}
|
||||
last_seconds = cs;
|
||||
tv->tv_sec = cs + clock_offset;
|
||||
tv->tv_usec = ((xtime_t)(clock_time () % CLOCK_SECOND))
|
||||
* 1000000L / CLOCK_SECOND;
|
||||
if (cs == clock_seconds ()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tz) {
|
||||
const struct tzoffset_info *tzo = &localtime_tzoffset;
|
||||
tz->tz_dsttime = is_dst (&tv->tv_sec, tzo);
|
||||
if (tz->tz_dsttime) {
|
||||
tz->tz_minuteswest = -tzo->dstoffset / 60;
|
||||
} else {
|
||||
tz->tz_minuteswest = -tzo->stdoffset / 60;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set time in seconds, microseconds ignored for now
|
||||
*/
|
||||
int xsettimeofday (const struct xtimeval *tv, const struct timezone *tz)
|
||||
{
|
||||
/* Don't allow setting timezone */
|
||||
if (tz) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
if (tv) {
|
||||
uint32_t cs;
|
||||
cs = clock_seconds ();
|
||||
clock_offset = tv->tv_sec - cs;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save timezone names into reserved string buffer and fill in the names
|
||||
* into the given tzoffset_info.
|
||||
* Return -1 on error, 0 for success.
|
||||
*/
|
||||
static int save_tznames
|
||||
( const char *stdname, const char *dstname
|
||||
, size_t stdlen, size_t dstlen
|
||||
, struct tzoffset_info *tzo
|
||||
)
|
||||
{
|
||||
size_t len = stdlen;
|
||||
if (stdname == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (dstname != NULL) {
|
||||
len += dstlen;
|
||||
}
|
||||
if (len + 2 > sizeof (tzo->namebuf)) {
|
||||
return -1;
|
||||
}
|
||||
tzo->stdname = tzo->namebuf;
|
||||
strncpy (tzo->namebuf, stdname, stdlen);
|
||||
tzo->namebuf [stdlen] = '\0';
|
||||
if (dstlen) {
|
||||
strncpy (tzo->namebuf + stdlen + 1, dstname, dstlen);
|
||||
tzo->namebuf [stdlen + 1 + dstlen] = '\0';
|
||||
tzo->dstname = tzo->namebuf + stdlen + 1;
|
||||
} else {
|
||||
tzo->dstname = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility functions for timezone string parsing (POSIX section 8)
|
||||
* Code adapted from OpenBSD localtime.c 1.57 2015/12/12 21:25:44
|
||||
* which is in the public domain.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The DST rules to use if TZ has no rules:
|
||||
* We default to US rules as of 1999-08-17.
|
||||
* POSIX 1003.1 section 8.1.1 says that the default DST rules are
|
||||
* implementation dependent; for historical reasons, US rules are a
|
||||
* common default.
|
||||
*/
|
||||
#ifndef TZDEFRULESTRING
|
||||
#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
|
||||
* year, a rule, and the offset from UTC at the time that rule takes effect,
|
||||
* calculate the Epoch-relative time that rule takes effect.
|
||||
*/
|
||||
|
||||
static xtime_t
|
||||
transtime(xtime_t janfirst, int year, const struct tzrule *rulep, long offset)
|
||||
{
|
||||
int leapyear;
|
||||
xtime_t value;
|
||||
int i;
|
||||
int d, m1, yy0, yy1, yy2, dow;
|
||||
|
||||
value = 0;
|
||||
leapyear = LEAP_YEAR (year);
|
||||
switch (rulep->r_type) {
|
||||
|
||||
case JULIAN_DAY:
|
||||
/*
|
||||
* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
|
||||
* years.
|
||||
* In non-leap years, or if the day number is 59 or less, just
|
||||
* add SECSPERDAY times the day number-1 to the time of
|
||||
* January 1, midnight, to get the day.
|
||||
*/
|
||||
value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
|
||||
if (leapyear && rulep->r_day >= 60) {
|
||||
value += SECSPERDAY;
|
||||
}
|
||||
break;
|
||||
|
||||
case DAY_OF_YEAR:
|
||||
/*
|
||||
* n - day of year.
|
||||
* Just add SECSPERDAY times the day number to the time of
|
||||
* January 1, midnight, to get the day.
|
||||
*/
|
||||
value = janfirst + rulep->r_day * SECSPERDAY;
|
||||
break;
|
||||
|
||||
case MONTH_NTH_DAY_OF_WEEK:
|
||||
/*
|
||||
* Mm.n.d - nth "dth day" of month m.
|
||||
*/
|
||||
value = janfirst;
|
||||
for (i = 0; i < rulep->r_mon - 1; ++i) {
|
||||
value += mon_lengths [leapyear][i] * SECSPERDAY;
|
||||
}
|
||||
|
||||
/*
|
||||
** Use Zeller's Congruence to get day-of-week of first day of
|
||||
** month.
|
||||
*/
|
||||
m1 = (rulep->r_mon + 9) % 12 + 1;
|
||||
yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
|
||||
yy1 = yy0 / 100;
|
||||
yy2 = yy0 % 100;
|
||||
dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
|
||||
if (dow < 0) {
|
||||
dow += DAYSPERWEEK;
|
||||
}
|
||||
|
||||
/*
|
||||
** "dow" is the day-of-week of the first day of the month. Get
|
||||
** the day-of-month (zero-origin) of the first "dow" day of the
|
||||
** month.
|
||||
*/
|
||||
d = rulep->r_day - dow;
|
||||
if (d < 0) {
|
||||
d += DAYSPERWEEK;
|
||||
}
|
||||
for (i = 1; i < rulep->r_week; ++i) {
|
||||
if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1]) {
|
||||
break;
|
||||
}
|
||||
d += DAYSPERWEEK;
|
||||
}
|
||||
|
||||
/*
|
||||
** "d" is the day-of-month (zero-origin) of the day we want.
|
||||
*/
|
||||
value += d * SECSPERDAY;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
|
||||
** question. To get the Epoch-relative time of the specified local
|
||||
** time on that day, add the transition time and the current offset
|
||||
** from UTC.
|
||||
*/
|
||||
return value + rulep->r_time + offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a pointer into a time zone string, scan until a character that is not
|
||||
* a valid character in a zone name is found. Return a pointer to that
|
||||
* character.
|
||||
*/
|
||||
|
||||
static const char *getzname (const char *s)
|
||||
{
|
||||
char c;
|
||||
while ((c = *s) != '\0' && !isdigit(c) && c != ',' && c != '-' && c != '+'){
|
||||
++s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a pointer into an extended time zone string, scan until the ending
|
||||
* delimiter of the zone name is located. Return a pointer to the delimiter.
|
||||
*
|
||||
* As with getzname above, the legal character set is actually quite
|
||||
* restricted, with other characters producing undefined results.
|
||||
* We don't do any checking here; checking is done later in common-case code.
|
||||
*/
|
||||
|
||||
static const char *getqzname (const char *strp, const int delim)
|
||||
{
|
||||
int c;
|
||||
while ((c = *strp) != '\0' && c != delim) {
|
||||
++strp;
|
||||
}
|
||||
return strp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a pointer into a time zone string, extract a number from that string.
|
||||
* Check that the number is within a specified range; if it is not, return
|
||||
* NULL.
|
||||
* Otherwise, return a pointer to the first character not part of the number.
|
||||
*/
|
||||
|
||||
static const char *getnum (const char *strp, int *nump, int min, int max)
|
||||
{
|
||||
char c;
|
||||
int num;
|
||||
|
||||
if (strp == NULL || !isdigit ((c = *strp))) {
|
||||
return NULL;
|
||||
}
|
||||
num = 0;
|
||||
do {
|
||||
num = num * 10 + (c - '0');
|
||||
if (num > max) {
|
||||
return NULL; /* illegal value */
|
||||
}
|
||||
c = *++strp;
|
||||
} while (isdigit (c));
|
||||
if (num < min) {
|
||||
return NULL; /* illegal value */
|
||||
}
|
||||
*nump = num;
|
||||
return strp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a pointer into a time zone string, extract a number of seconds,
|
||||
* in hh[:mm[:ss]] form, from the string.
|
||||
* If any error occurs, return NULL.
|
||||
* Otherwise, return a pointer to the first character not part of the number
|
||||
* of seconds.
|
||||
*/
|
||||
|
||||
static const char *getsecs (const char *strp, long *secsp)
|
||||
{
|
||||
int num;
|
||||
|
||||
/*
|
||||
* `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
|
||||
* "M10.4.6/26", which does not conform to Posix,
|
||||
* but which specifies the equivalent of
|
||||
* ``02:00 on the first Sunday on or after 23 Oct''.
|
||||
*/
|
||||
strp = getnum (strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
|
||||
if (strp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
*secsp = num * (long) SECSPERHOUR;
|
||||
if (*strp == ':') {
|
||||
++strp;
|
||||
strp = getnum (strp, &num, 0, MINSPERHOUR - 1);
|
||||
if (strp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
*secsp += num * SECSPERMIN;
|
||||
if (*strp == ':') {
|
||||
++strp;
|
||||
/* `SECSPERMIN' allows for leap seconds. */
|
||||
strp = getnum (strp, &num, 0, SECSPERMIN);
|
||||
if (strp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
*secsp += num;
|
||||
}
|
||||
}
|
||||
return strp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a pointer into a time zone string, extract an offset, in
|
||||
* [+-]hh[:mm[:ss]] form, from the string.
|
||||
* If any error occurs, return NULL.
|
||||
* Otherwise, return a pointer to the first character not part of the time.
|
||||
*/
|
||||
|
||||
static const char *getoffset (const char *strp, long *offsetp)
|
||||
{
|
||||
int neg = 0;
|
||||
|
||||
if (*strp == '-') {
|
||||
neg = 1;
|
||||
++strp;
|
||||
} else if (*strp == '+') {
|
||||
++strp;
|
||||
}
|
||||
strp = getsecs (strp, offsetp);
|
||||
if (strp == NULL) {
|
||||
return NULL; /* illegal time */
|
||||
}
|
||||
if (neg) {
|
||||
*offsetp = -*offsetp;
|
||||
}
|
||||
return strp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse (optionally extended) timezone name. Return pointer to
|
||||
* (undelimited) timezone name in tzn and length of same in len.
|
||||
* Return pointer to first character *after* name, NULL on error.
|
||||
* Factored from original tzparse function.
|
||||
*/
|
||||
static const char *
|
||||
egettzname (const char *strp, size_t *len, const char **tzn)
|
||||
{
|
||||
*tzn = strp;
|
||||
if (*strp == '<') {
|
||||
strp++;
|
||||
*tzn = strp;
|
||||
strp = getqzname (strp, '>');
|
||||
if (*strp != '>') {
|
||||
return NULL;
|
||||
}
|
||||
*len = strp - *tzn;
|
||||
strp++;
|
||||
} else {
|
||||
strp = getzname (strp);
|
||||
*len = strp - *tzn;
|
||||
}
|
||||
return strp;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given a pointer into a time zone string, extract a rule in the form
|
||||
** date[/time]. See POSIX section 8 for the format of "date" and "time".
|
||||
** If a valid rule is not found, return NULL.
|
||||
** Otherwise, return a pointer to the first character not part of the rule.
|
||||
*/
|
||||
|
||||
static const char *getrule (const char *strp, struct tzrule *rulep)
|
||||
{
|
||||
if (*strp == 'J') {
|
||||
/*
|
||||
* Julian day.
|
||||
*/
|
||||
rulep->r_type = JULIAN_DAY;
|
||||
++strp;
|
||||
strp = getnum (strp, &rulep->r_day, 1, DAYSPERNYEAR);
|
||||
} else if (*strp == 'M') {
|
||||
/*
|
||||
* Month, week, day.
|
||||
*/
|
||||
rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
|
||||
++strp;
|
||||
strp = getnum (strp, &rulep->r_mon, 1, MONSPERYEAR);
|
||||
if (strp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (*strp++ != '.') {
|
||||
return NULL;
|
||||
}
|
||||
strp = getnum (strp, &rulep->r_week, 1, 5);
|
||||
if (strp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (*strp++ != '.') {
|
||||
return NULL;
|
||||
}
|
||||
strp = getnum (strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
|
||||
} else if (isdigit (*strp)) {
|
||||
/*
|
||||
* Day of year.
|
||||
*/
|
||||
rulep->r_type = DAY_OF_YEAR;
|
||||
strp = getnum (strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
|
||||
} else {
|
||||
return NULL; /* invalid format */
|
||||
}
|
||||
if (strp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (*strp == '/') {
|
||||
/*
|
||||
* Time specified.
|
||||
*/
|
||||
++strp;
|
||||
strp = getsecs (strp, &rulep->r_time);
|
||||
} else {
|
||||
rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
|
||||
}
|
||||
return strp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse POSIX section 8 TZ string.
|
||||
* We keep the misnomer "name" for the timezone string.
|
||||
*/
|
||||
int tzparse (const char *name, struct tzoffset_info *tzo)
|
||||
{
|
||||
const char *stdname;
|
||||
const char *dstname;
|
||||
size_t stdlen;
|
||||
size_t dstlen;
|
||||
long stdoffset;
|
||||
long dstoffset;
|
||||
|
||||
dstname = NULL;
|
||||
stdname = name;
|
||||
name = egettzname (name, &stdlen, &stdname);
|
||||
if (name == NULL || *name == '\0') {
|
||||
return -1;
|
||||
}
|
||||
name = getoffset (name, &stdoffset);
|
||||
if (name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (*name != '\0') {
|
||||
name = egettzname (name, &dstlen, &dstname);
|
||||
if (name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (*name != '\0' && *name != ',' && *name != ';') {
|
||||
name = getoffset (name, &dstoffset);
|
||||
if (name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
dstoffset = stdoffset - SECSPERHOUR;
|
||||
}
|
||||
if (*name == '\0') {
|
||||
name = TZDEFRULESTRING;
|
||||
}
|
||||
if (*name == ',' || *name == ';') {
|
||||
struct tzrule start;
|
||||
struct tzrule end;
|
||||
++name;
|
||||
if ((name = getrule (name, &start)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (*name++ != ',') {
|
||||
return -1;
|
||||
}
|
||||
if ((name = getrule (name, &end)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (*name != '\0') {
|
||||
return -1;
|
||||
}
|
||||
if (save_tznames (stdname, dstname, stdlen, dstlen, tzo) != 0) {
|
||||
return -1;
|
||||
}
|
||||
tzo->start = start;
|
||||
tzo->end = end;
|
||||
tzo->stdoffset = stdoffset;
|
||||
tzo->dstoffset = dstoffset;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* only standard time, no DST */
|
||||
if (save_tznames (stdname, NULL, stdlen, 0, tzo) != 0) {
|
||||
return -1;
|
||||
}
|
||||
tzo->stdoffset = stdoffset;
|
||||
tzo->dstoffset = stdoffset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide a single static timezone which is used by localtime et.al.
|
||||
*/
|
||||
int set_tz (const char *tzstring)
|
||||
{
|
||||
return tzparse (tzstring, &localtime_tzoffset);
|
||||
}
|
||||
|
||||
static size_t lensecs (long seconds)
|
||||
{
|
||||
size_t len = 1;
|
||||
long secs = abs (seconds);
|
||||
if (seconds < 0) {
|
||||
len++;
|
||||
}
|
||||
if (secs / 3600 > 9) {
|
||||
len++;
|
||||
}
|
||||
if (secs % 3600) {
|
||||
len += 3;
|
||||
if (secs % 60) {
|
||||
len += 3;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get length of string resulting from serializing rule.
|
||||
*/
|
||||
static size_t lenrule (const struct tzrule *rule)
|
||||
{
|
||||
size_t len = 0;
|
||||
if (rule->r_type == JULIAN_DAY) {
|
||||
len++;
|
||||
}
|
||||
if (rule->r_type == JULIAN_DAY || rule->r_type == DAY_OF_YEAR) {
|
||||
len++;
|
||||
if (rule->r_day > 9) {
|
||||
len++;
|
||||
if (rule->r_day > 99) {
|
||||
len++;
|
||||
}
|
||||
}
|
||||
} else if (rule->r_type == MONTH_NTH_DAY_OF_WEEK) {
|
||||
len++;
|
||||
len++;
|
||||
if (rule->r_mon > 9) {
|
||||
len++;
|
||||
}
|
||||
len += 4; /* dots and week/day */
|
||||
if (rule->r_time != 7200) {
|
||||
len++;
|
||||
len += lensecs (rule->r_time);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int is_extended_name (const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i=0; name [i]; i++) {
|
||||
if (isdigit (name [i]) || name [i] == '+' || name [i] == '-') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get length of timezone string resulting from serializing tzo.
|
||||
*/
|
||||
static size_t len_tz_r (const struct tzoffset_info *tzo)
|
||||
{
|
||||
size_t len = 0;
|
||||
if (tzo->stdname == NULL) {
|
||||
return 0;
|
||||
}
|
||||
len = strlen (tzo->stdname);
|
||||
if (is_extended_name (tzo->stdname)) {
|
||||
len += 2;
|
||||
}
|
||||
len += lensecs (tzo->stdoffset);
|
||||
if (tzo->dstname) {
|
||||
len += strlen (tzo->dstname);
|
||||
if (is_extended_name (tzo->dstname)) {
|
||||
len += 2;
|
||||
}
|
||||
if (tzo->dstoffset - tzo->stdoffset != -3600) {
|
||||
len += lensecs (tzo->dstoffset);
|
||||
}
|
||||
len += 2; /* commas */
|
||||
len += lenrule (&tzo->start);
|
||||
len += lenrule (&tzo->end);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t len_tz (void)
|
||||
{
|
||||
return len_tz_r (&localtime_tzoffset);
|
||||
}
|
||||
|
||||
void appendsecs (char *buf, long minutes)
|
||||
{
|
||||
char *p = buf + strlen (buf);
|
||||
long min = abs (minutes);
|
||||
if (minutes < 0) {
|
||||
*p++ = '-';
|
||||
}
|
||||
if (min % 3600 == 0) {
|
||||
sprintf (p, "%ld", min / 3600);
|
||||
} else if (min % 60 == 0) {
|
||||
sprintf (p, "%ld:%ld", min / 3600, (min / 60) % 60);
|
||||
} else {
|
||||
sprintf (p, "%ld:%ld:%ld", min / 3600, (min / 60) % 60, min % 60);
|
||||
}
|
||||
}
|
||||
|
||||
void appendrule (char *buf, const struct tzrule *rule)
|
||||
{
|
||||
char *p = buf + strlen (buf);
|
||||
if (rule->r_type == JULIAN_DAY) {
|
||||
sprintf (p, "J%d", rule->r_day);
|
||||
} else if (rule->r_type == DAY_OF_YEAR) {
|
||||
sprintf (p, "%d", rule->r_day);
|
||||
} else if (rule->r_type == MONTH_NTH_DAY_OF_WEEK) {
|
||||
sprintf (p, "M%d.%d.%d", rule->r_mon, rule->r_week, rule->r_day);
|
||||
p = buf + strlen (buf);
|
||||
if (rule->r_time != 7200) {
|
||||
*p++ = '/';
|
||||
*p = '\0';
|
||||
appendsecs (p, rule->r_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *get_tz (char *buf, size_t buflen)
|
||||
{
|
||||
const struct tzoffset_info *tzo = &localtime_tzoffset;
|
||||
|
||||
if (tzo->stdname == NULL || len_tz_r (tzo) > buflen) {
|
||||
return NULL;
|
||||
}
|
||||
if (is_extended_name (tzo->stdname)) {
|
||||
sprintf (buf, "<%s>", tzo->stdname);
|
||||
} else {
|
||||
strcpy (buf, tzo->stdname);
|
||||
}
|
||||
appendsecs (buf, tzo->stdoffset);
|
||||
if (tzo->dstname != NULL) {
|
||||
if (is_extended_name (tzo->dstname)) {
|
||||
sprintf (buf + strlen (buf), "<%s>", tzo->dstname);
|
||||
} else {
|
||||
strcat (buf, tzo->dstname);
|
||||
}
|
||||
if (tzo->dstoffset - tzo->stdoffset != -3600) {
|
||||
appendsecs (buf, tzo->dstoffset);
|
||||
}
|
||||
strcat (buf, ",");
|
||||
appendrule (buf, &tzo->start);
|
||||
strcat (buf, ",");
|
||||
appendrule (buf, &tzo->end);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
|
@ -1,32 +0,0 @@
|
|||
/**
|
||||
* \addgroup Time related functions
|
||||
*
|
||||
* Resource definitions for time module
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Resource definitions for the time module
|
||||
*
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@tux.runtux.com>
|
||||
*/
|
||||
|
||||
#ifndef time_resource_h
|
||||
#define time_resource_h
|
||||
#include <assert.h>
|
||||
#include "contiki.h"
|
||||
#include "rest-engine.h"
|
||||
|
||||
extern resource_t res_timestamp;
|
||||
extern resource_t res_timezone;
|
||||
extern resource_t res_crontab;
|
||||
extern resource_t res_localtime;
|
||||
extern resource_t res_utc;
|
||||
|
||||
extern void activate_cron_resources (void);
|
||||
|
||||
#endif // time_resource_h
|
||||
/** @} */
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Timezone parsing
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Definitions for timezone parsing
|
||||
*
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@tux.runtux.com>
|
||||
*/
|
||||
|
||||
#ifndef tzparse_h
|
||||
#define tzparse_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Rule for DST switching
|
||||
*/
|
||||
struct tzrule {
|
||||
int r_type; /* type of rule--see below */
|
||||
int r_day; /* day number of rule */
|
||||
int r_week; /* week number of rule */
|
||||
int r_mon; /* month number of rule */
|
||||
long r_time; /* transition time of rule */
|
||||
};
|
||||
|
||||
#define JULIAN_DAY 0 /* Jn - Julian day */
|
||||
#define DAY_OF_YEAR 1 /* n - day of year */
|
||||
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
|
||||
|
||||
/*
|
||||
* Info about timezone offset handling.
|
||||
* We get at least a dstname and stdoffset, if no daylight saving is in
|
||||
* effect, dstname is NULL and no rule is filled in.
|
||||
*/
|
||||
struct tzoffset_info {
|
||||
const char *stdname;
|
||||
const char *dstname;
|
||||
long stdoffset;
|
||||
long dstoffset;
|
||||
struct tzrule start;
|
||||
struct tzrule end;
|
||||
char namebuf [TZ_MAX_CHARS];
|
||||
};
|
||||
|
||||
int tzparse (const char *name, struct tzoffset_info *tzo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // tzparse_h
|
|
@ -1,94 +0,0 @@
|
|||
/**
|
||||
* \defgroup Time related functions
|
||||
*
|
||||
* This rolls the necessary definition for getting/setting time and
|
||||
* managing local time into one include file, on posix systems this
|
||||
* lives in at least two include files, time.h and sys/time.h
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Definitions for the time module
|
||||
*
|
||||
* \author
|
||||
* Ralf Schlatterbeck <rsc@tux.runtux.com>
|
||||
*/
|
||||
|
||||
#ifndef xtime_h
|
||||
#define xtime_h
|
||||
|
||||
/* This is a time.h implementation but to avoid name-clashes with libs
|
||||
* trying to be helpfull we add the prefix x
|
||||
*/
|
||||
|
||||
#ifdef LOCAL_COMPILE
|
||||
#define clock_seconds() 1
|
||||
#define clock_time() 1
|
||||
#endif
|
||||
|
||||
#define DEFAULT_TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3"
|
||||
|
||||
typedef signed long long xtime_t;
|
||||
typedef signed long suseconds_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* tm_gmtoff and tm_zone are BSD additions */
|
||||
struct xtm {
|
||||
uint32_t tm_year; /* year */
|
||||
uint16_t tm_yday; /* day in the year */
|
||||
uint8_t tm_sec; /* seconds */
|
||||
uint8_t tm_min; /* minutes */
|
||||
uint8_t tm_hour; /* hours */
|
||||
uint8_t tm_mday; /* day of the month */
|
||||
uint8_t tm_mon; /* month */
|
||||
uint8_t tm_wday; /* day of the week */
|
||||
uint8_t tm_isdst; /* daylight saving time */
|
||||
int32_t tm_gmtoff; /* Seconds east of UTC */
|
||||
const char *tm_zone; /* Timezone abbreviation */
|
||||
};
|
||||
|
||||
struct xtimeval {
|
||||
xtime_t tv_sec; /* seconds */
|
||||
suseconds_t tv_usec; /* microseconds */
|
||||
};
|
||||
|
||||
struct timezone {
|
||||
int16_t tz_minuteswest; /* minutes west of Greenwich */
|
||||
int tz_dsttime; /* type of DST correction, unused */
|
||||
};
|
||||
|
||||
struct xtm *xgmtime (const xtime_t *timep);
|
||||
struct xtm *xgmtime_r (const xtime_t *timep, struct xtm *result);
|
||||
struct xtm *xlocaltime (const xtime_t *timep);
|
||||
struct xtm *xlocaltime_r (const xtime_t *timep, struct xtm *result);
|
||||
|
||||
int xgettimeofday (struct xtimeval *tv, struct timezone *tz);
|
||||
int xsettimeofday (const struct xtimeval *tv, const struct timezone *tz);
|
||||
|
||||
/*
|
||||
* Maximum length of all timezone names, this is much longer in UNIX
|
||||
* implementations but we have limited space here. Note that the length
|
||||
* includes a trailing \0 byte for each timezone name.
|
||||
*/
|
||||
#ifndef TZ_MAX_CHARS
|
||||
#define TZ_MAX_CHARS 16
|
||||
#endif
|
||||
|
||||
/* Maximum length of buffer to reserve for timezone string */
|
||||
#define MAXTZLEN (TZ_MAX_CHARS+9+2*(2+6+1+8)+1)
|
||||
|
||||
int set_tz (const char *tzstring);
|
||||
const char *get_tz (char *buffer, size_t buflen);
|
||||
size_t len_tz (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // xtime_h
|
||||
/** @} */
|
|
@ -1 +0,0 @@
|
|||
Subproject commit e95b02584a0041817da67c8c01f2a197d0c26915
|
|
@ -252,9 +252,8 @@ extern uip_ds6_netif_t uip_ds6_if;
|
|||
static unsigned short
|
||||
make_addresses(void *p)
|
||||
{
|
||||
uint8_t i, j = 0;
|
||||
uint16_t numprinted;
|
||||
|
||||
uint8_t i,j=0;
|
||||
uint16_t numprinted;
|
||||
numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh);
|
||||
for (i=0; i<UIP_DS6_ADDR_NB;i++) {
|
||||
if (uip_ds6_if.addr_list[i].isused) {
|
||||
|
@ -281,7 +280,7 @@ PT_THREAD(addresses(struct httpd_state *s, char *ptr))
|
|||
static unsigned short
|
||||
make_neighbors(void *p)
|
||||
{
|
||||
uint8_t j=0;
|
||||
uint8_t i,j=0;
|
||||
uint16_t numprinted;
|
||||
numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh);
|
||||
uip_ds6_nbr_t *nbr;
|
||||
|
@ -313,7 +312,7 @@ make_routes(void *p)
|
|||
static const char httpd_cgi_rtes1[] HTTPD_STRING_ATTR = "(%u (via ";
|
||||
static const char httpd_cgi_rtes2[] HTTPD_STRING_ATTR = ") %lus<br>";
|
||||
static const char httpd_cgi_rtes3[] HTTPD_STRING_ATTR = ")<br>";
|
||||
uint8_t j=0;
|
||||
uint8_t i,j=0;
|
||||
uint16_t numprinted;
|
||||
uip_ds6_route_t *r;
|
||||
|
||||
|
@ -324,7 +323,7 @@ make_routes(void *p)
|
|||
j++;
|
||||
numprinted += httpd_cgi_sprint_ip6(r->ipaddr, uip_appdata + numprinted);
|
||||
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes1, r->length);
|
||||
numprinted += httpd_cgi_sprint_ip6(*(uip_ds6_route_nexthop(r)), uip_appdata + numprinted);
|
||||
numprinted += httpd_cgi_sprint_ip6(uip_ds6_route_nexthop(r), uip_appdata + numprinted);
|
||||
if(r->state.lifetime < 3600) {
|
||||
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes2, r->state.lifetime);
|
||||
} else {
|
||||
|
|
|
@ -148,6 +148,13 @@
|
|||
#endif /* NBR_TABLE_FIND_REMOVABLE */
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
|
||||
/* RPL_CONF_MOP specifies the RPL mode of operation that will be
|
||||
* advertised by the RPL root. Possible values: RPL_MOP_NO_DOWNWARD_ROUTES,
|
||||
* RPL_MOP_NON_STORING, RPL_MOP_STORING_NO_MULTICAST, RPL_MOP_STORING_MULTICAST */
|
||||
#ifndef RPL_CONF_MOP
|
||||
#define RPL_CONF_MOP RPL_MOP_STORING_NO_MULTICAST
|
||||
#endif /* RPL_CONF_MOP */
|
||||
|
||||
/* UIP_CONF_MAX_ROUTES specifies the maximum number of routes that each
|
||||
node will be able to handle. */
|
||||
#ifndef UIP_CONF_MAX_ROUTES
|
||||
|
|
|
@ -47,8 +47,6 @@
|
|||
|
||||
#define IGNORE_CHAR(c) (c == 0x0d)
|
||||
#define END 0x0a
|
||||
//#define IGNORE_CHAR(c) (c == 0x0a)
|
||||
//#define END 0x0d
|
||||
|
||||
static struct ringbuf rxbuf;
|
||||
static uint8_t rxbuf_data[BUFSIZE];
|
||||
|
|
|
@ -107,6 +107,9 @@ slip_send(void)
|
|||
|
||||
ptr = &uip_buf[UIP_LLH_LEN];
|
||||
for(i = 0; i < uip_len; ++i) {
|
||||
if(i == UIP_TCPIP_HLEN) {
|
||||
ptr = (uint8_t *)uip_appdata;
|
||||
}
|
||||
c = *ptr++;
|
||||
if(c == SLIP_END) {
|
||||
slip_arch_writeb(SLIP_ESC);
|
||||
|
@ -158,7 +161,6 @@ rxbuf_init(void)
|
|||
static uint16_t
|
||||
slip_poll_handler(uint8_t *outbuf, uint16_t blen)
|
||||
{
|
||||
#ifdef SLIP_CONF_MICROSOFT_CHAT
|
||||
/* This is a hack and won't work across buffer edge! */
|
||||
if(rxbuf[begin] == 'C') {
|
||||
int i;
|
||||
|
@ -175,8 +177,6 @@ slip_poll_handler(uint8_t *outbuf, uint16_t blen)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* SLIP_CONF_MICROSOFT_CHAT */
|
||||
|
||||
#ifdef SLIP_CONF_ANSWER_MAC_REQUEST
|
||||
else if(rxbuf[begin] == '?') {
|
||||
/* Used by tapslip6 to request mac for auto configure */
|
||||
|
@ -425,13 +425,11 @@ slip_input_byte(unsigned char c)
|
|||
}
|
||||
rxbuf[cur_end] = c;
|
||||
|
||||
#ifdef SLIP_CONF_MICROSOFT_CHAT
|
||||
/* There could be a separate poll routine for this. */
|
||||
if(c == 'T' && rxbuf[begin] == 'C') {
|
||||
process_poll(&slip_process);
|
||||
return 1;
|
||||
}
|
||||
#endif /* SLIP_CONF_MICROSOFT_CHAT */
|
||||
|
||||
if(c == SLIP_END) {
|
||||
/*
|
||||
|
|
|
@ -83,7 +83,7 @@ ringbufindex_peek_put(const struct ringbufindex *r)
|
|||
if(((r->put_ptr - r->get_ptr) & r->mask) == r->mask) {
|
||||
return -1;
|
||||
}
|
||||
return r->put_ptr;
|
||||
return (r->put_ptr + 1) & r->mask;
|
||||
}
|
||||
/* Remove the first element and return its index */
|
||||
int
|
||||
|
@ -118,7 +118,7 @@ ringbufindex_peek_get(const struct ringbufindex *r)
|
|||
first one. If there are no bytes left, we return -1.
|
||||
*/
|
||||
if(((r->put_ptr - r->get_ptr) & r->mask) > 0) {
|
||||
return r->get_ptr;
|
||||
return (r->get_ptr + 1) & r->mask;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -48,72 +48,25 @@ struct ringbufindex {
|
|||
uint8_t put_ptr, get_ptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Initialize a ring buffer. The size must be a power of two
|
||||
* \param r Pointer to ringbufindex
|
||||
* \param size Size of ring buffer
|
||||
*/
|
||||
/* Initialize a ring buffer. The size must be a power of two */
|
||||
void ringbufindex_init(struct ringbufindex *r, uint8_t size);
|
||||
|
||||
/**
|
||||
* \brief Put one element to the ring buffer
|
||||
* \param r Pointer to ringbufindex
|
||||
* \retval 0 Failure; the ring buffer is full
|
||||
* \retval 1 Success; an element is added
|
||||
*/
|
||||
/* Put one element to the ring buffer */
|
||||
int ringbufindex_put(struct ringbufindex *r);
|
||||
|
||||
/**
|
||||
* \brief Check if there is space to put an element.
|
||||
* \param r Pinter to ringbufindex
|
||||
* \retval >= 0 The index where the next element is to be added.
|
||||
* \retval -1 Failure; the ring buffer is full
|
||||
*/
|
||||
/* Check if there is space to put an element.
|
||||
* Return the index where the next element is to be added */
|
||||
int ringbufindex_peek_put(const struct ringbufindex *r);
|
||||
|
||||
/**
|
||||
* \brief Remove the first element and return its index
|
||||
* \param r Pinter to ringbufindex
|
||||
* \retval >= 0 The index of the first element
|
||||
* \retval -1 No element in the ring buffer
|
||||
*/
|
||||
/* Remove the first element and return its index */
|
||||
int ringbufindex_get(struct ringbufindex *r);
|
||||
|
||||
/**
|
||||
* \brief Return the index of the first element which will be removed if calling
|
||||
* ringbufindex_get.
|
||||
* \param r Pinter to ringbufindex
|
||||
* \retval >= 0 The index of the first element
|
||||
* \retval -1 No element in the ring buffer
|
||||
*/
|
||||
/* Return the index of the first element
|
||||
* (which will be removed if calling ringbufindex_peek) */
|
||||
int ringbufindex_peek_get(const struct ringbufindex *r);
|
||||
|
||||
/**
|
||||
* \brief Return the ring buffer size
|
||||
* \param r Pinter to ringbufindex
|
||||
* \return The size of the ring buffer
|
||||
*/
|
||||
/* Return the ring buffer size */
|
||||
int ringbufindex_size(const struct ringbufindex *r);
|
||||
|
||||
/**
|
||||
* \brief Return the number of elements currently in the ring buffer.
|
||||
* \param r Pinter to ringbufindex
|
||||
* \return The number of elements in the ring buffer
|
||||
*/
|
||||
/* Return the number of elements currently in the ring buffer */
|
||||
int ringbufindex_elements(const struct ringbufindex *r);
|
||||
|
||||
/**
|
||||
* \brief Is the ring buffer full?
|
||||
* \retval 0 Not full
|
||||
* \retval 1 Full
|
||||
*/
|
||||
/* Is the ring buffer full? */
|
||||
int ringbufindex_full(const struct ringbufindex *r);
|
||||
|
||||
/**
|
||||
* \brief Is the ring buffer empty?
|
||||
* \retval 0 Not empty
|
||||
* \retval 1 Empty
|
||||
*/
|
||||
/* Is the ring buffer empty? */
|
||||
int ringbufindex_empty(const struct ringbufindex *r);
|
||||
|
||||
#endif /* __RINGBUFINDEX_H__ */
|
||||
|
|
|
@ -130,7 +130,7 @@ typedef uint16_t settings_length_t;
|
|||
|
||||
#define SETTINGS_KEY_RDC_INDEX TCC('R','D') /*!< RDC index, uint8_t */
|
||||
#define SETTINGS_KEY_CHANNEL_MASK TCC('C','M') /*!< Channel mask, uint16_t */
|
||||
#define SETTINGS_KEY_MAC_CONF TCC('M','C') /*!< MAC Layer Config, uint8_t */
|
||||
|
||||
/*****************************************************************************/
|
||||
// MARK: - Constants
|
||||
|
||||
|
|
|
@ -35,10 +35,6 @@
|
|||
#include <string.h>
|
||||
|
||||
#define printf(...)
|
||||
|
||||
static uip_ip6addr_t ip64_prefix = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0}};
|
||||
static uint8_t ip64_prefix_len = 96;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ip64_addr_copy4(uip_ip4addr_t *dest, const uip_ip4addr_t *src)
|
||||
|
@ -60,7 +56,20 @@ ip64_addr_4to6(const uip_ip4addr_t *ipv4addr,
|
|||
addresses. It returns 0 if it failed to convert the address and
|
||||
non-zero if it could successfully convert the address. */
|
||||
|
||||
uip_ipaddr_copy(ipv6addr, &ip64_prefix);
|
||||
/* The IPv4 address is encoded as an IPv6-encoded IPv4 address in
|
||||
the ::ffff:0000/24 prefix.*/
|
||||
ipv6addr->u8[0] = 0;
|
||||
ipv6addr->u8[1] = 0;
|
||||
ipv6addr->u8[2] = 0;
|
||||
ipv6addr->u8[3] = 0;
|
||||
ipv6addr->u8[4] = 0;
|
||||
ipv6addr->u8[5] = 0;
|
||||
ipv6addr->u8[6] = 0;
|
||||
ipv6addr->u8[7] = 0;
|
||||
ipv6addr->u8[8] = 0;
|
||||
ipv6addr->u8[9] = 0;
|
||||
ipv6addr->u8[10] = 0xff;
|
||||
ipv6addr->u8[11] = 0xff;
|
||||
ipv6addr->u8[12] = ipv4addr->u8[0];
|
||||
ipv6addr->u8[13] = ipv4addr->u8[1];
|
||||
ipv6addr->u8[14] = ipv4addr->u8[2];
|
||||
|
@ -81,7 +90,21 @@ ip64_addr_6to4(const uip_ip6addr_t *ipv6addr,
|
|||
returns 0 if it failed to convert the address and non-zero if it
|
||||
could successfully convert the address. */
|
||||
|
||||
if(ip64_addr_is_ip64(ipv6addr)) {
|
||||
/* If the IPv6 address is an IPv6-encoded
|
||||
IPv4 address (i.e. in the ::ffff:0/8 prefix), we simply use the
|
||||
IPv4 addresses directly. */
|
||||
if(ipv6addr->u8[0] == 0 &&
|
||||
ipv6addr->u8[1] == 0 &&
|
||||
ipv6addr->u8[2] == 0 &&
|
||||
ipv6addr->u8[3] == 0 &&
|
||||
ipv6addr->u8[4] == 0 &&
|
||||
ipv6addr->u8[5] == 0 &&
|
||||
ipv6addr->u8[6] == 0 &&
|
||||
ipv6addr->u8[7] == 0 &&
|
||||
ipv6addr->u8[8] == 0 &&
|
||||
ipv6addr->u8[9] == 0 &&
|
||||
ipv6addr->u8[10] == 0xff &&
|
||||
ipv6addr->u8[11] == 0xff) {
|
||||
ipv4addr->u8[0] = ipv6addr->u8[12];
|
||||
ipv4addr->u8[1] = ipv6addr->u8[13];
|
||||
ipv4addr->u8[2] = ipv6addr->u8[14];
|
||||
|
@ -98,16 +121,3 @@ ip64_addr_6to4(const uip_ip6addr_t *ipv6addr,
|
|||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
ip64_addr_is_ip64(const uip_ip6addr_t *ipv6addr)
|
||||
{
|
||||
return uip_ipaddr_prefixcmp(ipv6addr, &ip64_prefix, ip64_prefix_len);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ip64_addr_set_prefix(const uip_ip6addr_t *prefix, uint8_t prefix_len)
|
||||
{
|
||||
uip_ipaddr_copy(&ip64_prefix, prefix);
|
||||
ip64_prefix_len = prefix_len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -58,9 +58,6 @@ int ip64_addr_6to4(const uip_ip6addr_t *ipv6addr,
|
|||
int ip64_addr_4to6(const uip_ip4addr_t *ipv4addr,
|
||||
uip_ip6addr_t *ipv6addr);
|
||||
|
||||
int ip64_addr_is_ip64(const uip_ip6addr_t *ipv6addr);
|
||||
|
||||
void ip64_addr_set_prefix(const uip_ip6addr_t *prefix, uint8_t prefix_len);
|
||||
|
||||
#endif /* IP64_ADDR_H */
|
||||
|
||||
|
|
|
@ -1094,7 +1094,7 @@ resolv_set_hostname(const char *hostname)
|
|||
/* Add the .local suffix if it isn't already there */
|
||||
if(strlen(resolv_hostname) < 7 ||
|
||||
strcasecmp(resolv_hostname + strlen(resolv_hostname) - 6, ".local") != 0) {
|
||||
strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE - strlen(resolv_hostname));
|
||||
strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE);
|
||||
}
|
||||
|
||||
PRINTF("resolver: hostname changed to \"%s\"\n", resolv_hostname);
|
||||
|
@ -1248,8 +1248,8 @@ remove_trailing_dots(const char *name) {
|
|||
static char dns_name_without_dots[RESOLV_CONF_MAX_DOMAIN_NAME_SIZE + 1];
|
||||
size_t len = strlen(name);
|
||||
|
||||
if(len && name[len - 1] == '.') {
|
||||
strncpy(dns_name_without_dots, name, RESOLV_CONF_MAX_DOMAIN_NAME_SIZE);
|
||||
if(name[len - 1] == '.') {
|
||||
strncpy(dns_name_without_dots, name, sizeof(dns_name_without_dots));
|
||||
while(len && (dns_name_without_dots[len - 1] == '.')) {
|
||||
dns_name_without_dots[--len] = 0;
|
||||
}
|
||||
|
@ -1309,7 +1309,7 @@ resolv_query(const char *name)
|
|||
|
||||
memset(nameptr, 0, sizeof(*nameptr));
|
||||
|
||||
strncpy(nameptr->name, name, sizeof(nameptr->name) - 1);
|
||||
strncpy(nameptr->name, name, sizeof(nameptr->name));
|
||||
nameptr->state = STATE_NEW;
|
||||
nameptr->seqno = seqno;
|
||||
++seqno;
|
||||
|
@ -1479,7 +1479,7 @@ resolv_found(char *name, uip_ipaddr_t * ipaddr)
|
|||
}
|
||||
|
||||
/* Re-add the .local suffix */
|
||||
strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE - strlen(resolv_hostname));
|
||||
strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE);
|
||||
|
||||
start_name_collision_check(CLOCK_SECOND * 5);
|
||||
} else if(mdns_state == MDNS_STATE_READY) {
|
||||
|
|
|
@ -102,6 +102,9 @@ slipdev_send(void)
|
|||
|
||||
ptr = &uip_buf[UIP_LLH_LEN];
|
||||
for(i = 0; i < uip_len; ++i) {
|
||||
if(i == UIP_TCPIP_HLEN) {
|
||||
ptr = (uint8_t *)uip_appdata;
|
||||
}
|
||||
c = *ptr++;
|
||||
switch(c) {
|
||||
case SLIP_END:
|
||||
|
|
|
@ -490,8 +490,26 @@ void uip_reass_over(void);
|
|||
*
|
||||
* The uip_aligned_buf array is used to hold incoming and outgoing
|
||||
* packets. The device driver should place incoming data into this
|
||||
* buffer. When sending data, the device driver should read the
|
||||
* outgoing data from this buffer.
|
||||
* buffer. When sending data, the device driver should read the link
|
||||
* level headers and the TCP/IP headers from this buffer. The size of
|
||||
* the link level headers is configured by the UIP_LLH_LEN define.
|
||||
*
|
||||
* \note The application data need not be placed in this buffer, so
|
||||
* the device driver must read it from the place pointed to by the
|
||||
* uip_appdata pointer as illustrated by the following example:
|
||||
\code
|
||||
void
|
||||
devicedriver_send(void)
|
||||
{
|
||||
hwsend(&uip_buf[0], UIP_LLH_LEN);
|
||||
if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
|
||||
hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
|
||||
} else {
|
||||
hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
|
||||
hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
typedef union {
|
||||
|
|
|
@ -120,6 +120,10 @@ uint16_t uip_ipchksum(void);
|
|||
* The TCP checksum is the Internet checksum of data contents of the
|
||||
* TCP segment, and a pseudo-header as defined in RFC793.
|
||||
*
|
||||
* \note The uip_appdata pointer that points to the packet data may
|
||||
* point anywhere in memory, so it is not possible to simply calculate
|
||||
* the Internet checksum of the contents of the uip_buf buffer.
|
||||
*
|
||||
* \return The TCP checksum of the TCP segment in uip_buf and pointed
|
||||
* to by uip_appdata.
|
||||
*/
|
||||
|
|
|
@ -163,6 +163,7 @@ create_msg(CC_REGISTER_ARG struct dhcp_msg *m)
|
|||
memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len);
|
||||
|
||||
memset(m->sname, 0, sizeof(m->sname));
|
||||
strcpy((char *)m->sname, "Thingsquare");
|
||||
memset(m->file, 0, sizeof(m->file));
|
||||
|
||||
|
||||
|
|
|
@ -39,9 +39,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
PROCESS(ip64_ipv4_dhcp_process, "IPv4 DHCP");
|
||||
|
||||
uip_ipaddr_t uip_hostaddr; /* Needed because it is referenced by dhcpc.c */
|
||||
|
@ -51,7 +48,7 @@ uip_ipaddr_t uip_hostaddr; /* Needed because it is referenced by dhcpc.c */
|
|||
void
|
||||
ip64_ipv4_dhcp_init(void)
|
||||
{
|
||||
printf("IP64: Starting DHCPv4\n");
|
||||
printf("Starting DHCPv4\n");
|
||||
process_start(&ip64_ipv4_dhcp_process, NULL);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -61,10 +58,10 @@ PROCESS_THREAD(ip64_ipv4_dhcp_process, ev, data)
|
|||
|
||||
ip64_dhcpc_init(&ip64_eth_addr, sizeof(ip64_eth_addr));
|
||||
|
||||
PRINTF("IP64: Inited\n");
|
||||
printf("Inited\n");
|
||||
|
||||
ip64_dhcpc_request();
|
||||
PRINTF("IP64: Requested\n");
|
||||
printf("Requested\n");
|
||||
while(1) {
|
||||
PROCESS_WAIT_EVENT();
|
||||
|
||||
|
@ -81,22 +78,15 @@ void
|
|||
ip64_dhcpc_configured(const struct ip64_dhcpc_state *s)
|
||||
{
|
||||
uip_ip6addr_t ip6dnsaddr;
|
||||
PRINTF("IP64: DHCP Configured with %d.%d.%d.%d\n",
|
||||
printf("DHCP Configured with %d.%d.%d.%d\n",
|
||||
s->ipaddr.u8[0], s->ipaddr.u8[1],
|
||||
s->ipaddr.u8[2], s->ipaddr.u8[3]);
|
||||
|
||||
ip64_set_hostaddr((uip_ip4addr_t *)&s->ipaddr);
|
||||
ip64_set_netmask((uip_ip4addr_t *)&s->netmask);
|
||||
ip64_set_draddr((uip_ip4addr_t *)&s->default_router);
|
||||
if(!uip_ip4addr_cmp((uip_ip4addr_t *)&s->dnsaddr, &uip_all_zeroes_addr)) {
|
||||
/* Note: Currently we assume only one DNS server */
|
||||
uip_ipaddr_t * dns = uip_nameserver_get(0);
|
||||
/* Only update DNS entry if it is empty or already IPv4 */
|
||||
if(uip_is_addr_unspecified(dns) || ip64_addr_is_ip64(dns)) {
|
||||
ip64_addr_4to6((uip_ip4addr_t *)&s->dnsaddr, &ip6dnsaddr);
|
||||
uip_nameserver_update(&ip6dnsaddr, uip_ntohs(s->lease_time[0])*65536ul + uip_ntohs(s->lease_time[1]));
|
||||
}
|
||||
}
|
||||
// mdns_conf(&ip6dnsaddr);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
|
|
|
@ -162,7 +162,7 @@ struct uip_mcast6_driver {
|
|||
#define UIP_MCAST6 smrf_driver
|
||||
|
||||
#elif UIP_MCAST6_ENGINE == UIP_MCAST6_ENGINE_ESMRF
|
||||
#define RPL_WITH_MULTICAST 1
|
||||
#define RPL_CONF_MULTICAST 1
|
||||
#define UIP_MCAST6 esmrf_driver
|
||||
|
||||
#else
|
||||
|
|
|
@ -547,8 +547,8 @@ websocket_open(struct websocket *s, const char *url,
|
|||
websocket_callback c)
|
||||
{
|
||||
int ret;
|
||||
char host[MAX_HOSTLEN + 1] = {0};
|
||||
char path[MAX_PATHLEN + 1] = {0};
|
||||
char host[MAX_HOSTLEN];
|
||||
char path[MAX_PATHLEN];
|
||||
uint16_t port;
|
||||
uip_ipaddr_t addr;
|
||||
|
||||
|
|
|
@ -365,8 +365,6 @@ powercycle_turn_radio_on(void)
|
|||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
volatile uint8_t mcusleepcycle=16;
|
||||
|
||||
static void
|
||||
powercycle_wrapper(struct rtimer *t, void *ptr)
|
||||
{
|
||||
|
@ -481,8 +479,8 @@ powercycle(struct rtimer *t, void *ptr)
|
|||
break;
|
||||
}
|
||||
|
||||
// schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME);
|
||||
// PT_YIELD(&pt);
|
||||
schedule_powercycle(t, CCA_CHECK_TIME + CCA_SLEEP_TIME);
|
||||
PT_YIELD(&pt);
|
||||
}
|
||||
if(radio_is_on) {
|
||||
if(!(NETSTACK_RADIO.receiving_packet() ||
|
||||
|
@ -502,15 +500,14 @@ powercycle(struct rtimer *t, void *ptr)
|
|||
ensure an occasional wake cycle or foreground processing will
|
||||
be blocked until a packet is detected */
|
||||
#if RDC_CONF_MCU_SLEEP
|
||||
|
||||
static uint8_t sleepcycle;
|
||||
if((sleepcycle++ < mcusleepcycle) && !we_are_sending && !radio_is_on && !(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet())) {
|
||||
rtimer_arch_sleep(cycle_start - RTIMER_NOW());
|
||||
if((sleepcycle++ < 16) && !we_are_sending && !radio_is_on) {
|
||||
rtimer_arch_sleep(RTIMER_NOW() - cycle_start);
|
||||
} else {
|
||||
sleepcycle = 0;
|
||||
#ifndef RDC_CONF_PT_YIELD_OFF
|
||||
schedule_powercycle_fixed(t, cycle_start);
|
||||
PT_YIELD(&pt);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
schedule_powercycle_fixed(t, cycle_start);
|
||||
|
@ -551,11 +548,11 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
|
|||
rtimer_clock_t t0;
|
||||
#if WITH_PHASE_OPTIMIZATION
|
||||
rtimer_clock_t encounter_time = 0;
|
||||
uint8_t is_known_receiver = 0;
|
||||
#endif
|
||||
int strobes;
|
||||
uint8_t got_strobe_ack = 0;
|
||||
uint8_t is_broadcast = 0;
|
||||
uint8_t is_known_receiver = 0;
|
||||
uint8_t collisions;
|
||||
int transmit_len;
|
||||
int ret;
|
||||
|
@ -715,13 +712,11 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
|
|||
|
||||
watchdog_periodic();
|
||||
|
||||
#if WITH_PHASE_OPTIMIZATION
|
||||
if(!is_broadcast && (is_receiver_awake || is_known_receiver) &&
|
||||
!RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + MAX_PHASE_STROBE_TIME)) {
|
||||
PRINTF("miss to %d\n", packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[0]);
|
||||
break;
|
||||
}
|
||||
#endif /* WITH_PHASE_OPTIMIZATION */
|
||||
|
||||
#if !RDC_CONF_HARDWARE_ACK
|
||||
len = 0;
|
||||
|
|
|
@ -183,7 +183,7 @@ frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest
|
|||
} else {
|
||||
/* No PAN ID in ACK */
|
||||
if(fcf->frame_type != FRAME802154_ACKFRAME) {
|
||||
if(!fcf->panid_compression && (fcf->src_addr_mode & 3)) {
|
||||
if(!fcf->panid_compression && fcf->src_addr_mode & 3) {
|
||||
/* If compressed, don't include source PAN ID */
|
||||
src_pan_id = 1;
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest
|
|||
int
|
||||
frame802154_check_dest_panid(frame802154_t *frame)
|
||||
{
|
||||
int has_dest_panid = 0;
|
||||
int has_dest_panid;
|
||||
|
||||
if(frame == NULL) {
|
||||
return 0;
|
||||
|
@ -304,7 +304,7 @@ field_len(frame802154_t *p, field_length_t *flen)
|
|||
* up to the caller. */
|
||||
if(p->fcf.frame_version < FRAME802154_IEEE802154E_2012) {
|
||||
/* Set PAN ID compression bit if src pan id matches dest pan id. */
|
||||
if((p->fcf.dest_addr_mode & 3) && (p->fcf.src_addr_mode & 3) &&
|
||||
if(p->fcf.dest_addr_mode & 3 && p->fcf.src_addr_mode & 3 &&
|
||||
p->src_pid == p->dest_pid) {
|
||||
p->fcf.panid_compression = 1;
|
||||
} else {
|
||||
|
@ -362,20 +362,6 @@ frame802154_hdrlen(frame802154_t *p)
|
|||
return 2 + flen.seqno_len + flen.dest_pid_len + flen.dest_addr_len +
|
||||
flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len;
|
||||
}
|
||||
void
|
||||
frame802154_create_fcf(frame802154_fcf_t *fcf, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (fcf->frame_type & 7) |
|
||||
((fcf->security_enabled & 1) << 3) |
|
||||
((fcf->frame_pending & 1) << 4) |
|
||||
((fcf->ack_required & 1) << 5) |
|
||||
((fcf->panid_compression & 1) << 6);
|
||||
buf[1] = ((fcf->sequence_number_suppression & 1)) |
|
||||
((fcf->ie_list_present & 1)) << 1 |
|
||||
((fcf->dest_addr_mode & 3) << 2) |
|
||||
((fcf->frame_version & 3) << 4) |
|
||||
((fcf->src_addr_mode & 3) << 6);
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Creates a frame for transmission over the air. This function is
|
||||
|
@ -402,7 +388,17 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
|
|||
|
||||
/* OK, now we have field lengths. Time to actually construct */
|
||||
/* the outgoing frame, and store it in buf */
|
||||
frame802154_create_fcf(&p->fcf, buf);
|
||||
buf[0] = (p->fcf.frame_type & 7) |
|
||||
((p->fcf.security_enabled & 1) << 3) |
|
||||
((p->fcf.frame_pending & 1) << 4) |
|
||||
((p->fcf.ack_required & 1) << 5) |
|
||||
((p->fcf.panid_compression & 1) << 6);
|
||||
buf[1] = ((p->fcf.sequence_number_suppression & 1)) |
|
||||
((p->fcf.ie_list_present & 1)) << 1 |
|
||||
((p->fcf.dest_addr_mode & 3) << 2) |
|
||||
((p->fcf.frame_version & 3) << 4) |
|
||||
((p->fcf.src_addr_mode & 3) << 6);
|
||||
|
||||
pos = 2;
|
||||
|
||||
/* Sequence number */
|
||||
|
@ -464,28 +460,6 @@ frame802154_create(frame802154_t *p, uint8_t *buf)
|
|||
|
||||
return (int)pos;
|
||||
}
|
||||
|
||||
void
|
||||
frame802154_parse_fcf(uint8_t *data, frame802154_fcf_t *pfcf)
|
||||
{
|
||||
frame802154_fcf_t fcf;
|
||||
|
||||
/* decode the FCF */
|
||||
fcf.frame_type = data[0] & 7;
|
||||
fcf.security_enabled = (data[0] >> 3) & 1;
|
||||
fcf.frame_pending = (data[0] >> 4) & 1;
|
||||
fcf.ack_required = (data[0] >> 5) & 1;
|
||||
fcf.panid_compression = (data[0] >> 6) & 1;
|
||||
|
||||
fcf.sequence_number_suppression = data[1] & 1;
|
||||
fcf.ie_list_present = (data[1] >> 1) & 1;
|
||||
fcf.dest_addr_mode = (data[1] >> 2) & 3;
|
||||
fcf.frame_version = (data[1] >> 4) & 3;
|
||||
fcf.src_addr_mode = (data[1] >> 6) & 3;
|
||||
|
||||
/* copy fcf */
|
||||
memcpy(pfcf, &fcf, sizeof(frame802154_fcf_t));
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Parses an input frame. Scans the input frame to find each
|
||||
|
@ -515,7 +489,19 @@ frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
|
|||
p = data;
|
||||
|
||||
/* decode the FCF */
|
||||
frame802154_parse_fcf(p, &fcf);
|
||||
fcf.frame_type = p[0] & 7;
|
||||
fcf.security_enabled = (p[0] >> 3) & 1;
|
||||
fcf.frame_pending = (p[0] >> 4) & 1;
|
||||
fcf.ack_required = (p[0] >> 5) & 1;
|
||||
fcf.panid_compression = (p[0] >> 6) & 1;
|
||||
|
||||
fcf.sequence_number_suppression = p[1] & 1;
|
||||
fcf.ie_list_present = (p[1] >> 1) & 1;
|
||||
fcf.dest_addr_mode = (p[1] >> 2) & 3;
|
||||
fcf.frame_version = (p[1] >> 4) & 3;
|
||||
fcf.src_addr_mode = (p[1] >> 6) & 3;
|
||||
|
||||
/* copy fcf and seqNum */
|
||||
memcpy(&pf->fcf, &fcf, sizeof(frame802154_fcf_t));
|
||||
p += 2; /* Skip first two bytes */
|
||||
|
||||
|
|
|
@ -207,10 +207,8 @@ typedef struct {
|
|||
/* Prototypes */
|
||||
|
||||
int frame802154_hdrlen(frame802154_t *p);
|
||||
void frame802154_create_fcf(frame802154_fcf_t *fcf, uint8_t *buf);
|
||||
int frame802154_create(frame802154_t *p, uint8_t *buf);
|
||||
int frame802154_parse(uint8_t *data, int length, frame802154_t *pf);
|
||||
void frame802154_parse_fcf(uint8_t *data, frame802154_fcf_t *pfcf);
|
||||
|
||||
/* Get current PAN ID */
|
||||
uint16_t frame802154_get_pan_id(void);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# IEEE 802.15.4-2015 TSCH and IETF 6TiSCH
|
||||
# IEEE 802.15.4e TSCH (TimeSlotted Channel Hopping)
|
||||
|
||||
## Overview
|
||||
|
||||
Time Slotted Channel Hopping (TSCH) is a MAC layer of the [IEEE 802.15.4e-2012 amendment][ieee802.15.4e-2012],
|
||||
TSCH is a MAC layer of the [IEEE 802.15.4e-2012 amendment][ieee802.15.4e-2012],
|
||||
currently being integrated as part of the new IEEE 802.15.4-2015.
|
||||
[6TiSCH][ietf-6tisch-wg] is an IETF Working Group focused on IPv6 over TSCH.
|
||||
This is a Contiki implementation of TSCH and the 6TiSCH so-called "minimal configuration",
|
||||
|
@ -13,9 +13,7 @@ It was developped by:
|
|||
* Beshr Al Nahas, SICS (now Chalmers University), beshr@chalmers.se, github user: [beshrns](https://github.com/beshrns)
|
||||
* Atis Elsts, Univ. Bristol, atis.elsts@bristol.ac.uk, github user: [atiselsts](https://github.com/atiselsts)
|
||||
|
||||
|
||||
This implementation is presented in depth and evaluated in our paper: [*TSCH and 6TiSCH for Contiki: Challenges, Design and Evaluation*](http://www.simonduquennoy.net/papers/duquennoy17tsch.pdf), IEEE DCOSS'17.
|
||||
The scheduler Orchestra is detailled in [*Orchestra: Robust Mesh Networks Through Autonomously Scheduled TSCH*](http://www.simonduquennoy.net/papers/duquennoy15orchestra.pdf), ACM SenSys'15.
|
||||
You can find an extensive evaluation of this implementation in our paper [*Orchestra: Robust Mesh Networks Through Autonomously Scheduled TSCH*](http://www.simonduquennoy.net/papers/duquennoy15orchestra.pdf), ACM SenSys'15.
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -29,7 +27,7 @@ This implementation includes:
|
|||
* Standard TSCH link selection and slot operation (10ms slots by default)
|
||||
* Standard TSCH synchronization, including with ACK/NACK time correction Information Element
|
||||
* Standard TSCH queues and CSMA-CA mechanism
|
||||
* Standard TSCH and 6TiSCH security
|
||||
* Standard TSCH security
|
||||
* Standard 6TiSCH TSCH-RPL interaction (6TiSCH Minimal Configuration and Minimal Schedule)
|
||||
* A scheduling API to add/remove slotframes and links
|
||||
* A system for logging from TSCH timeslot operation interrupt, with postponed printout
|
||||
|
|
|
@ -202,7 +202,6 @@ tsch_queue_flush_nbr_queue(struct tsch_neighbor *n)
|
|||
/* Free packet queuebuf */
|
||||
tsch_queue_free_packet(p);
|
||||
}
|
||||
PRINTF("TSCH-queue: packet is deleted packet=%p\n", p);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -254,8 +253,6 @@ tsch_queue_add_packet(const linkaddr_t *addr, mac_callback_t sent, void *ptr)
|
|||
/* Add to ringbuf (actual add committed through atomic operation) */
|
||||
n->tx_array[put_index] = p;
|
||||
ringbufindex_put(&n->tx_ringbuf);
|
||||
PRINTF("TSCH-queue: packet is added put_index=%u, packet=%p\n",
|
||||
put_index, p);
|
||||
return p;
|
||||
} else {
|
||||
memb_free(&packet_memb, p);
|
||||
|
@ -291,7 +288,6 @@ tsch_queue_remove_packet_from_queue(struct tsch_neighbor *n)
|
|||
/* Get and remove packet from ringbuf (remove committed through an atomic operation */
|
||||
int16_t get_index = ringbufindex_get(&n->tx_ringbuf);
|
||||
if(get_index != -1) {
|
||||
PRINTF("TSCH-queue: packet is removed, get_index=%u\n", get_index);
|
||||
return n->tx_array[get_index];
|
||||
} else {
|
||||
return NULL;
|
||||
|
|
|
@ -99,12 +99,13 @@ create_dag_callback(void *ptr)
|
|||
rpl_dag_t *dag;
|
||||
|
||||
dag = rpl_get_any_dag();
|
||||
|
||||
PRINTF("RPL: Found a network we did not create\n");
|
||||
PRINTF("RPL: version %d grounded %d preference %d used %d joined %d rank %d\n",
|
||||
#if DEBUG
|
||||
printf("Found a network we did not create\n");
|
||||
printf("version %d grounded %d preference %d used %d joined %d rank %d\n",
|
||||
dag->version, dag->grounded,
|
||||
dag->preference, dag->used,
|
||||
dag->joined, dag->rank);
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* We found a RPL network that we did not create so we just join
|
||||
it without becoming root. But if the network has an infinite
|
||||
|
@ -222,14 +223,14 @@ rpl_dag_root_init_dag_immediately(void)
|
|||
|
||||
uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
|
||||
rpl_set_prefix(dag, &prefix, 64);
|
||||
PRINTF("RPL: rpl_dag_root_init_dag: created a new RPL dag\n");
|
||||
PRINTF("rpl_dag_root_init_dag: created a new RPL dag\n");
|
||||
return 0;
|
||||
} else {
|
||||
PRINTF("RPL: rpl_dag_root_init_dag: failed to create a new RPL DAG\n");
|
||||
PRINTF("rpl_dag_root_init_dag: failed to create a new RPL DAG\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
PRINTF("RPL: rpl_dag_root_init_dag: failed to create a new RPL DAG, no preferred IP address found\n");
|
||||
PRINTF("rpl_dag_root_init_dag: failed to create a new RPL DAG, no preferred IP address found\n");
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -525,10 +525,10 @@ rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, unsigned len)
|
|||
/* Autoconfigure an address if this node does not already have an address
|
||||
with this prefix. Otherwise, update the prefix */
|
||||
if(last_len == 0) {
|
||||
PRINTF("RPL: rpl_set_prefix - prefix NULL\n");
|
||||
PRINTF("rpl_set_prefix - prefix NULL\n");
|
||||
check_prefix(NULL, &dag->prefix_info);
|
||||
} else {
|
||||
PRINTF("RPL: rpl_set_prefix - prefix NON-NULL\n");
|
||||
PRINTF("rpl_set_prefix - prefix NON-NULL\n");
|
||||
check_prefix(&last_prefix, &dag->prefix_info);
|
||||
}
|
||||
return 1;
|
||||
|
@ -983,7 +983,7 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
|
|||
PRINTF("RPL: Removing default route ");
|
||||
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
|
||||
PRINTF("\n");
|
||||
PRINTF("RPL: rpl_move_parent\n");
|
||||
PRINTF("rpl_move_parent\n");
|
||||
uip_ds6_defrt_rm(dag_src->instance->def_route);
|
||||
dag_src->instance->def_route = NULL;
|
||||
}
|
||||
|
@ -1546,7 +1546,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
|||
|
||||
/* The DIO comes from a valid DAG, we can refresh its lifetime */
|
||||
dag->lifetime = (1UL << (instance->dio_intmin + instance->dio_intdoubl)) * RPL_DAG_LIFETIME / 1000;
|
||||
PRINTF("RPL: Set dag ");
|
||||
PRINTF("Set dag ");
|
||||
PRINT6ADDR(&dag->dag_id);
|
||||
PRINTF(" lifetime to %ld\n", dag->lifetime);
|
||||
|
||||
|
|
|
@ -507,10 +507,10 @@ update_hbh_header(void)
|
|||
if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) {
|
||||
if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR;
|
||||
PRINTF("RPL: Forwarding error\n");
|
||||
PRINTF("RPL forwarding error\n");
|
||||
/* We should send back the packet to the originating parent,
|
||||
but it is not feasible yet, so we send a No-Path DAO instead */
|
||||
PRINTF("RPL: Generate No-Path DAO\n");
|
||||
PRINTF("RPL generate No-Path DAO\n");
|
||||
parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||
if(parent != NULL) {
|
||||
dao_output_target(parent, &UIP_IP_BUF->destipaddr, RPL_ZERO_LIFETIME);
|
||||
|
@ -526,11 +526,11 @@ update_hbh_header(void)
|
|||
/* No route was found, so this packet will go towards the RPL
|
||||
root. If so, we should not set the down flag. */
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN;
|
||||
PRINTF("RPL: Option going up\n");
|
||||
PRINTF("RPL option going up\n");
|
||||
} else {
|
||||
/* A DAO route was found so we set the down flag. */
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN;
|
||||
PRINTF("RPL: Option going down\n");
|
||||
PRINTF("RPL option going down\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -644,17 +644,11 @@ rpl_update_header(void)
|
|||
/* At the root, remove headers if any, and insert SRH or HBH
|
||||
* (SRH is inserted only if the destination is in the DODAG) */
|
||||
rpl_remove_header();
|
||||
if(rpl_get_dag(&UIP_IP_BUF->destipaddr) != NULL) {
|
||||
/* dest is in a DODAG; the packet is going down. */
|
||||
if(RPL_IS_NON_STORING(default_instance)) {
|
||||
return insert_srh_header();
|
||||
} else {
|
||||
return insert_hbh_header(default_instance);
|
||||
}
|
||||
} else {
|
||||
/* dest is outside of DODAGs; no ext header is needed. */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)
|
||||
&& UIP_IP_BUF->ttl == uip_ds6_if.cur_hop_limit) {
|
||||
|
|
|
@ -158,8 +158,8 @@ get_global_addr(uip_ipaddr_t *addr)
|
|||
static uint32_t
|
||||
get32(uint8_t *buffer, int pos)
|
||||
{
|
||||
return ((uint32_t)buffer[pos] << 24 | (uint32_t)buffer[pos + 1] << 16 |
|
||||
(uint32_t)buffer[pos + 2] << 8 | buffer[pos + 3]);
|
||||
return (uint32_t)buffer[pos] << 24 | (uint32_t)buffer[pos + 1] << 16 |
|
||||
(uint32_t)buffer[pos + 2] << 8 | buffer[pos + 3];
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
|
@ -202,7 +202,7 @@ rpl_icmp6_update_nbr_table(uip_ipaddr_t *from, nbr_table_reason_t reason, void *
|
|||
}
|
||||
|
||||
return nbr;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
dis_input(void)
|
||||
|
@ -218,14 +218,15 @@ dis_input(void)
|
|||
for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES;
|
||||
instance < end; ++instance) {
|
||||
if(instance->used == 1) {
|
||||
if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
#if RPL_LEAF_ONLY
|
||||
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
PRINTF("RPL: LEAF ONLY Multicast DIS will NOT reset DIO timer\n");
|
||||
#else /* !RPL_LEAF_ONLY */
|
||||
if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
PRINTF("RPL: Multicast DIS => reset DIO timer\n");
|
||||
rpl_reset_dio_timer(instance);
|
||||
#endif /* !RPL_LEAF_ONLY */
|
||||
} else {
|
||||
#endif /* !RPL_LEAF_ONLY */
|
||||
/* Check if this neighbor should be added according to the policy. */
|
||||
if(rpl_icmp6_update_nbr_table(&UIP_IP_BUF->srcipaddr,
|
||||
NBR_TABLE_REASON_RPL_DIS, NULL) == NULL) {
|
||||
|
@ -461,7 +462,7 @@ dio_input(void)
|
|||
|
||||
rpl_process_dio(&from, &dio);
|
||||
|
||||
discard:
|
||||
discard:
|
||||
uip_clear_buf();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -652,7 +653,6 @@ dao_input_storing(void)
|
|||
|
||||
prefixlen = 0;
|
||||
parent = NULL;
|
||||
memset(&prefix, 0, sizeof(prefix));
|
||||
|
||||
uip_ipaddr_copy(&dao_sender_addr, &UIP_IP_BUF->srcipaddr);
|
||||
|
||||
|
@ -749,11 +749,6 @@ dao_input_storing(void)
|
|||
|
||||
#if RPL_WITH_MULTICAST
|
||||
if(uip_is_addr_mcast_global(&prefix)) {
|
||||
/*
|
||||
* "rep" is used for a unicast route which we don't need now; so set NULL so
|
||||
* that operations on "rep" will be skipped.
|
||||
*/
|
||||
rep = NULL;
|
||||
mcast_group = uip_mcast6_route_add(&prefix);
|
||||
if(mcast_group) {
|
||||
mcast_group->dag = dag;
|
||||
|
@ -850,7 +845,6 @@ fwd_dao:
|
|||
int should_ack = 0;
|
||||
|
||||
if(flags & RPL_DAO_K_FLAG) {
|
||||
if(rep != NULL) {
|
||||
/*
|
||||
* check if this route is already installed and we can ack now!
|
||||
* not pending - and same seq-no means that we can ack.
|
||||
|
@ -863,12 +857,10 @@ fwd_dao:
|
|||
should_ack = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dag->preferred_parent != NULL &&
|
||||
rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) {
|
||||
uint8_t out_seq = 0;
|
||||
if(rep != NULL) {
|
||||
/* if this is pending and we get the same seq no it is a retrans */
|
||||
if(RPL_ROUTE_IS_DAO_PENDING(rep) &&
|
||||
rep->state.dao_seqno_in == sequence) {
|
||||
|
@ -877,7 +869,6 @@ fwd_dao:
|
|||
} else {
|
||||
out_seq = prepare_for_dao_fwd(sequence, rep);
|
||||
}
|
||||
}
|
||||
|
||||
PRINTF("RPL: Forwarding DAO to parent ");
|
||||
PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
|
||||
|
@ -1027,7 +1018,7 @@ dao_input(void)
|
|||
dao_input_nonstoring();
|
||||
}
|
||||
|
||||
discard:
|
||||
discard:
|
||||
uip_clear_buf();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -1151,30 +1142,30 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
|
|||
}
|
||||
|
||||
if(parent == NULL) {
|
||||
PRINTF("RPL: dao_output_target error parent NULL\n");
|
||||
PRINTF("RPL dao_output_target error parent NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
parent_ipaddr = rpl_get_parent_ipaddr(parent);
|
||||
if(parent_ipaddr == NULL) {
|
||||
PRINTF("RPL: dao_output_target error parent IP address NULL\n");
|
||||
PRINTF("RPL dao_output_target error parent IP address NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dag = parent->dag;
|
||||
if(dag == NULL) {
|
||||
PRINTF("RPL: dao_output_target error dag NULL\n");
|
||||
PRINTF("RPL dao_output_target error dag NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
instance = dag->instance;
|
||||
|
||||
if(instance == NULL) {
|
||||
PRINTF("RPL: dao_output_target error instance NULL\n");
|
||||
PRINTF("RPL dao_output_target error instance NULL\n");
|
||||
return;
|
||||
}
|
||||
if(prefix == NULL) {
|
||||
PRINTF("RPL: dao_output_target error prefix NULL\n");
|
||||
PRINTF("RPL dao_output_target error prefix NULL\n");
|
||||
return;
|
||||
}
|
||||
#ifdef RPL_DEBUG_DAO_OUTPUT
|
||||
|
|
|
@ -177,7 +177,7 @@ find_removable_dis(uip_ipaddr_t *from)
|
|||
if(num_free > 0) {
|
||||
/* there are free entries (e.g. unsused by RPL and ND6) but since it is
|
||||
used by other modules we can not pick these entries for removal. */
|
||||
PRINTF("NBR-POLICY: Num-free > 0 = %d - Other for RPL/ND6 unused NBR entry exists .",
|
||||
PRINTF("Num-free > 0 = %d - Other for RPL/ND6 unused NBR entry exists .",
|
||||
num_free);
|
||||
}
|
||||
if(num_children < MAX_CHILDREN) {
|
||||
|
@ -195,20 +195,20 @@ find_removable_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
|||
|
||||
instance = rpl_get_instance(dio->instance_id);
|
||||
if(instance == NULL || instance->current_dag == NULL) {
|
||||
PRINTF("NBR-POLICY: Did not find instance id: %d\n", dio->instance_id);
|
||||
PRINTF("Did not find instance id: %d\n", dio->instance_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add the new neighbor only if it is better than the worst parent. */
|
||||
if(dio->rank + instance->min_hoprankinc < worst_rank - instance->min_hoprankinc / 2) {
|
||||
/* Found *great* neighbor - add! */
|
||||
PRINTF("NBR-POLICY: Found better neighbor %d < %d - add to cache...\n",
|
||||
PRINTF("Found better neighbor %d < %d - add to cache...\n",
|
||||
dio->rank, worst_rank);
|
||||
|
||||
return worst_rank_nbr;
|
||||
}
|
||||
|
||||
PRINTF("NBR-POLICY: Found worse neighbor with new %d and old %d - NOT add to cache.\n",
|
||||
PRINTF("Found worse neighbor with new %d and old %d - NOT add to cache.\n",
|
||||
dio->rank, worst_rank);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ find_removable_dao(uip_ipaddr_t *from, rpl_instance_t *instance)
|
|||
/* Check if this DAO sender is not yet neighbor and there is already too
|
||||
many children. */
|
||||
if(num_children >= max) {
|
||||
PRINTF("NBR-POLICY: Can not add another child - already at max.\n");
|
||||
PRINTF("Can not add another child - already at max.\n");
|
||||
return NULL;
|
||||
}
|
||||
/* remove the worst ranked nbr */
|
||||
|
|
|
@ -91,13 +91,13 @@ rpl_set_mode(enum rpl_mode m)
|
|||
|
||||
PRINTF("RPL: switching to feather mode\n");
|
||||
if(default_instance != NULL) {
|
||||
PRINTF("RPL: rpl_set_mode: RPL sending DAO with zero lifetime\n");
|
||||
PRINTF("rpl_set_mode: RPL sending DAO with zero lifetime\n");
|
||||
if(default_instance->current_dag != NULL) {
|
||||
dao_output(default_instance->current_dag->preferred_parent, RPL_ZERO_LIFETIME);
|
||||
}
|
||||
rpl_cancel_dao(default_instance);
|
||||
} else {
|
||||
PRINTF("RPL: rpl_set_mode: no default instance\n");
|
||||
PRINTF("rpl_set_mode: no default instance\n");
|
||||
}
|
||||
|
||||
mode = m;
|
||||
|
@ -143,7 +143,7 @@ rpl_purge_routes(void)
|
|||
uip_ipaddr_copy(&prefix, &r->ipaddr);
|
||||
uip_ds6_route_rm(r);
|
||||
r = uip_ds6_route_head();
|
||||
PRINTF("RPL: No more routes to ");
|
||||
PRINTF("No more routes to ");
|
||||
PRINT6ADDR(&prefix);
|
||||
dag = default_instance->current_dag;
|
||||
/* Propagate this information with a No-Path DAO to preferred parent if we are not a RPL Root */
|
||||
|
@ -313,7 +313,7 @@ rpl_purge_dags(void)
|
|||
if(instance->dag_table[i].used) {
|
||||
if(instance->dag_table[i].lifetime == 0) {
|
||||
if(!instance->dag_table[i].joined) {
|
||||
PRINTF("RPL: Removing dag ");
|
||||
PRINTF("Removing dag ");
|
||||
PRINT6ADDR(&instance->dag_table[i].dag_id);
|
||||
PRINTF("\n");
|
||||
rpl_free_dag(&instance->dag_table[i]);
|
||||
|
@ -331,7 +331,7 @@ void
|
|||
rpl_init(void)
|
||||
{
|
||||
uip_ipaddr_t rplmaddr;
|
||||
PRINTF("RPL: RPL started\n");
|
||||
PRINTF("RPL started\n");
|
||||
default_instance = NULL;
|
||||
|
||||
rpl_dag_init();
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Inria.
|
||||
* 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Default log levels for a number of modules
|
||||
* \author
|
||||
* Simon Duquennoy <simon.duquennoy@inria.fr>
|
||||
*/
|
||||
|
||||
/** \addtogroup sys
|
||||
* @{ */
|
||||
|
||||
/** \addtogroup log
|
||||
* @{ */
|
||||
|
||||
#ifndef __LOG_CONF_H__
|
||||
#define __LOG_CONF_H__
|
||||
|
||||
/* Log only the last 16 bytes of link-layer and IPv6 addresses */
|
||||
#ifdef LOG_CONF_WITH_COMPACT_ADDR
|
||||
#define LOG_WITH_COMPACT_ADDR LOG_CONF_WITH_COMPACT_ADDR
|
||||
#else /* LOG_CONF_WITH_COMPACT_ADDR */
|
||||
#define LOG_WITH_COMPACT_ADDR 0
|
||||
#endif /* LOG_CONF_WITH_COMPACT_ADDR */
|
||||
|
||||
/* Prefix all logs with file name and line-of-code */
|
||||
#ifdef LOG_CONF_WITH_LOC
|
||||
#define LOG_WITH_LOC LOG_CONF_WITH_LOC
|
||||
#else /* LOG_CONF_WITH_LOC */
|
||||
#define LOG_WITH_LOC 0
|
||||
#endif /* LOG_CONF_WITH_LOC */
|
||||
|
||||
/* Prefix all logs with Module name and logging level */
|
||||
#ifdef LOG_CONF_WITH_MODULE_PREFIX
|
||||
#define LOG_WITH_MODULE_PREFIX LOG_CONF_WITH_MODULE_PREFIX
|
||||
#else /* LOG_CONF_WITH_MODULE_PREFIX */
|
||||
#define LOG_WITH_MODULE_PREFIX 1
|
||||
#endif /* LOG_CONF_WITH_MODULE_PREFIX */
|
||||
|
||||
/* Cooja annotations */
|
||||
#ifdef LOG_CONF_WITH_ANNOTATE
|
||||
#define LOG_WITH_ANNOTATE LOG_CONF_WITH_ANNOTATE
|
||||
#else /* LOG_CONF_WITH_ANNOTATE */
|
||||
#define LOG_WITH_ANNOTATE 0
|
||||
#endif /* LOG_CONF_WITH_ANNOTATE */
|
||||
|
||||
/* Custom output function -- default is printf */
|
||||
#ifdef LOG_CONF_OUTPUT
|
||||
#define LOG_OUTPUT(...) LOG_CONF_OUTPUT(__VA_ARGS__)
|
||||
#else /* LOG_CONF_OUTPUT */
|
||||
#define LOG_OUTPUT(...) printf(__VA_ARGS__)
|
||||
#endif /* LOG_CONF_OUTPUT */
|
||||
|
||||
/*
|
||||
* Custom output function to prefix logs with level and module.
|
||||
*
|
||||
* This will only be called when LOG_CONF_WITH_MODULE_PREFIX is enabled and
|
||||
* all implementations should be based on LOG_OUTPUT.
|
||||
*
|
||||
* \param level The log level
|
||||
* \param levelstr The log level as string
|
||||
* \param module The module string descriptor
|
||||
*/
|
||||
#ifdef LOG_CONF_OUTPUT_PREFIX
|
||||
#define LOG_OUTPUT_PREFIX(level, levelstr, module) LOG_CONF_OUTPUT_PREFIX(level, levelstr, module)
|
||||
#else /* LOG_CONF_OUTPUT_PREFIX */
|
||||
#define LOG_OUTPUT_PREFIX(level, levelstr, module) LOG_OUTPUT("[%-4s: %-10s] ", levelstr, module)
|
||||
#endif /* LOG_CONF_OUTPUT_PREFIX */
|
||||
|
||||
/******************************************************************************/
|
||||
/********************* A list of currently supported modules ******************/
|
||||
/******************************************************************************/
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_RPL
|
||||
#define LOG_CONF_LEVEL_RPL LOG_LEVEL_NONE /* Only for rpl-lite */
|
||||
#endif /* LOG_CONF_LEVEL_RPL */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_TCPIP
|
||||
#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_NONE
|
||||
#endif /* LOG_CONF_LEVEL_TCPIP */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_IPV6
|
||||
#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_NONE
|
||||
#endif /* LOG_CONF_LEVEL_IPV6 */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_6LOWPAN
|
||||
#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_NONE
|
||||
#endif /* LOG_CONF_LEVEL_6LOWPAN */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_NULLNET
|
||||
#define LOG_CONF_LEVEL_NULLNET LOG_LEVEL_NONE
|
||||
#endif /* LOG_CONF_LEVEL_NULLNET */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_MAC
|
||||
#define LOG_CONF_LEVEL_MAC LOG_LEVEL_NONE
|
||||
#endif /* LOG_CONF_LEVEL_MAC */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_FRAMER
|
||||
#define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_NONE
|
||||
#endif /* LOG_CONF_LEVEL_FRAMER */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_6TOP
|
||||
#define LOG_CONF_LEVEL_6TOP LOG_LEVEL_NONE
|
||||
#endif /* LOG_CONF_LEVEL_6TOP */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_COAP
|
||||
#define LOG_CONF_LEVEL_COAP LOG_LEVEL_NONE
|
||||
#endif /* LOG_CONF_LEVEL_COAP */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_LWM2M
|
||||
#define LOG_CONF_LEVEL_LWM2M LOG_LEVEL_NONE
|
||||
#endif /* LOG_CONF_LEVEL_LWM2M */
|
||||
|
||||
#ifndef LOG_CONF_LEVEL_MAIN
|
||||
#define LOG_CONF_LEVEL_MAIN LOG_LEVEL_INFO
|
||||
#endif /* LOG_CONF_LEVEL_MAIN */
|
||||
|
||||
#endif /* __LOG_CONF_H__ */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
|
@ -68,6 +68,7 @@ typedef unsigned short uip_stats_t;
|
|||
#define UIP_ARCH_ADD32 1
|
||||
#define UIP_ARCH_CHKSUM 1
|
||||
|
||||
#define UIP_CONF_LLH_LEN 14
|
||||
#define RESOLV_CONF_SUPPORTS_MDNS 0
|
||||
#define RESOLV_CONF_SUPPORTS_RECORD_EXPIRATION 0
|
||||
|
||||
|
@ -79,12 +80,6 @@ void logscr(const void *msg, unsigned len);
|
|||
#define logscr(msg, len) write(STDERR_FILENO, msg, len)
|
||||
#endif
|
||||
|
||||
#if WITH_SLIP
|
||||
#define UIP_CONF_LLH_LEN 0
|
||||
#else /* WITH_SLIP */
|
||||
#define UIP_CONF_LLH_LEN 14
|
||||
#endif /* WITH_SLIP */
|
||||
|
||||
#if MTU_SIZE
|
||||
#define UIP_CONF_BUFFER_SIZE (UIP_LLH_LEN + MTU_SIZE)
|
||||
#else /* MTU_SIZE */
|
||||
|
|
|
@ -31,10 +31,6 @@
|
|||
# Author: Oliver Schmidt <ol.sc@web.de>
|
||||
#
|
||||
|
||||
ifdef SLIP
|
||||
DEFINES += WITH_SLIP
|
||||
endif
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
CONTIKI_TARGET_DIRS = . lib sys
|
||||
|
@ -43,7 +39,7 @@ CONTIKI_CPU_DIRS = . lib sys ctk net
|
|||
CONTIKI_TARGET_SOURCEFILES += contiki-main.c
|
||||
CONTIKI_CPU_SOURCEFILES += log.c error.c unload.c config.c ctk-mouse.c \
|
||||
clock.c mtarch.c mtarch-asm.S lc-asm.S \
|
||||
uip_arch.c slip_arch.c ethernet-drv.c ethernet.c
|
||||
uip_arch.c ethernet-drv.c ethernet.c
|
||||
|
||||
ETHERNET_SOURCEFILES = cs8900a.S lan91c96.S w5100.S
|
||||
|
||||
|
@ -67,7 +63,7 @@ AR = ar65
|
|||
# The apps coming with Contiki run even on a 0x100 byte stack.
|
||||
|
||||
ASFLAGS = -t $(TARGET)
|
||||
CFLAGS += -t $(TARGET) -Ors -W -unused-param
|
||||
CFLAGS += -t $(TARGET) -Or -W -unused-param
|
||||
LDFLAGS = -t $(TARGET) -m contiki-$(TARGET).map -D __STACKSIZE__=0x200
|
||||
AROPTS = a
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ cc65 compiler [http://cc65.github.io/cc65/](http://cc65.github.io/cc65/).
|
|||
|
||||
The Contiki network configuration for 6502-based targets is loaded from a
|
||||
binary configuration file (by default named contiki.cfg). It has the following
|
||||
format for Ethernet:
|
||||
format:
|
||||
|
||||
- Bytes 1 - 4: IP Address (HiByte first)
|
||||
- Bytes 5 - 8: Subnet Mask (HiByte first)
|
||||
|
@ -15,13 +15,10 @@ format for Ethernet:
|
|||
- Bytes 17 - 18: Ethernet card I/O address (LoByte first !)
|
||||
- Bytes 19 - xx: Ethernet card driver name (ASCII / PETSCII)
|
||||
|
||||
It has the following format for SLIP (based on RS232 driver coming with cc65):
|
||||
An online Contiki configuration file generator is available at two sites:
|
||||
|
||||
- Bytes 1 - 4: IP Address (HiByte first)
|
||||
- Bytes 5 - 8: Subnet Mask (HiByte first)
|
||||
- Bytes 9 - 12: Default Router (HiByte first)
|
||||
- Bytes 13 - 16: DNS Server (HiByte first)
|
||||
- Bytes 17 - 21: struct ser_params (see cc65 serial.h)
|
||||
- [http://www.a2retrosystems.com/contiki.html](http://www.a2retrosystems.com/contiki.html)
|
||||
- [http://contiki.cbm8bit.com](http://contiki.cbm8bit.com)
|
||||
|
||||
The build for 6502-based machines includes the 'disk' make goal which creates a
|
||||
bootable floppy disk image containing the project binary, a sample
|
||||
|
@ -35,11 +32,6 @@ make goal. The values of the high-level configuration macros are not tracked by
|
|||
the build so a manual rebuild is necessary on any change. The following
|
||||
high-level configuration macros may be set:
|
||||
|
||||
- WITH_SLIP
|
||||
- Default: 0
|
||||
- Purpose: Use SLIP (based on RS232 driver coming with cc65) instead of
|
||||
Ethernet.
|
||||
|
||||
- MTU_SIZE
|
||||
- Default: 1500
|
||||
- Purpose: Set the Maximum Transfer Unit size.
|
||||
|
@ -86,10 +78,6 @@ high-level configuration macros may be set:
|
|||
- Default: 0
|
||||
- Purpose: Enable CTK mouse support and load a mouse driver.
|
||||
|
||||
- STATIC_MOUSE
|
||||
- Default: N/A
|
||||
- Purpose: Link mouse driver statically instead of loading it dynamically.
|
||||
|
||||
- WITH_ARGS
|
||||
- Default: 0
|
||||
- Purpose: Enable support for contiki_argc / contiki_argv.
|
||||
|
|
|
@ -49,15 +49,6 @@ static uint8_t okay;
|
|||
void
|
||||
ctk_mouse_init(void)
|
||||
{
|
||||
#ifdef STATIC_MOUSE
|
||||
|
||||
okay = mouse_install(&mouse_def_callbacks, &STATIC_MOUSE) == MOUSE_ERR_OK;
|
||||
if(okay) {
|
||||
atexit((void (*)(void))mouse_uninstall);
|
||||
}
|
||||
|
||||
#else /* STATIC_MOUSE */
|
||||
|
||||
struct mod_ctrl module_control = {cfs_read};
|
||||
|
||||
module_control.callerdata = cfs_open("contiki.mou", CFS_READ);
|
||||
|
@ -74,8 +65,6 @@ ctk_mouse_init(void)
|
|||
}
|
||||
cfs_close(module_control.callerdata);
|
||||
}
|
||||
|
||||
#endif /* STATIC_MOUSE */
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
unsigned short
|
||||
|
|
|
@ -42,7 +42,6 @@ choose(uint8_t max)
|
|||
exit(0);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
return val - '0';
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -66,13 +65,13 @@ main(void)
|
|||
d = choose(d) - 1;
|
||||
|
||||
#ifdef __APPLE2__
|
||||
printf("Slot (1-7)\n");
|
||||
printf("\nSlot (1-7)\n");
|
||||
drivers[d].address += choose(7) * 0x10;
|
||||
#endif
|
||||
|
||||
f = cfs_open("contiki.cfg", CFS_WRITE);
|
||||
if(f == -1) {
|
||||
printf("Saving Config - Error\n");
|
||||
printf("\nSaving Config - Error\n");
|
||||
return;
|
||||
}
|
||||
cfs_write(f, ipcfg, sizeof(ipcfg));
|
||||
|
@ -80,6 +79,6 @@ main(void)
|
|||
cfs_write(f, drivers[d].driver, strlen(drivers[d].driver));
|
||||
cfs_close(f);
|
||||
|
||||
printf("Saving Config - Done\n");
|
||||
printf("\nSaving Config - Done\n");
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -39,24 +39,7 @@
|
|||
#include "cfs/cfs.h"
|
||||
#include "sys/log.h"
|
||||
#include "lib/error.h"
|
||||
|
||||
#include "lib/config.h"
|
||||
|
||||
struct {
|
||||
uip_ipaddr_t hostaddr;
|
||||
uip_ipaddr_t netmask;
|
||||
uip_ipaddr_t draddr;
|
||||
uip_ipaddr_t resolvaddr;
|
||||
union {
|
||||
struct {
|
||||
uint16_t addr;
|
||||
#ifndef STATIC_DRIVER
|
||||
char name[12+1];
|
||||
#endif /* !STATIC_DRIVER */
|
||||
} ethernet;
|
||||
uint8_t slip[5];
|
||||
};
|
||||
} config;
|
||||
#include "net/ethernet-drv.h"
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if LOG_CONF_ENABLED
|
||||
|
@ -76,9 +59,16 @@ ipaddrtoa(uip_ipaddr_t *ipaddr, char *buffer)
|
|||
}
|
||||
#endif /* LOG_CONF_ENABLED */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
struct ethernet_config *
|
||||
config_read(char *filename)
|
||||
{
|
||||
static struct {
|
||||
uip_ipaddr_t hostaddr;
|
||||
uip_ipaddr_t netmask;
|
||||
uip_ipaddr_t draddr;
|
||||
uip_ipaddr_t resolvaddr;
|
||||
struct ethernet_config ethernetcfg;
|
||||
} config;
|
||||
int file;
|
||||
|
||||
file = cfs_open(filename, CFS_READ);
|
||||
|
@ -87,8 +77,8 @@ config_read(char *filename)
|
|||
error_exit();
|
||||
}
|
||||
|
||||
if(cfs_read(file, &config, sizeof(config)) < sizeof(uip_ipaddr_t) * 4
|
||||
+ sizeof(uint16_t)) {
|
||||
if(cfs_read(file, &config, sizeof(config)) < sizeof(config)
|
||||
- sizeof(config.ethernetcfg.name)) {
|
||||
log_message(filename, ": No config file");
|
||||
error_exit();
|
||||
}
|
||||
|
@ -100,22 +90,16 @@ config_read(char *filename)
|
|||
log_message("Def. Router: ", ipaddrtoa(&config.draddr, uip_buf));
|
||||
log_message("DNS Server: ", ipaddrtoa(&config.resolvaddr, uip_buf));
|
||||
|
||||
#ifdef STATIC_DRIVER
|
||||
#ifndef STATIC_DRIVER
|
||||
log_message("Eth. Driver: ", config.ethernetcfg.name);
|
||||
#else /* !STATIC_DRIVER */
|
||||
#define _stringize(arg) #arg
|
||||
#define stringize(arg) _stringize(arg)
|
||||
#if WITH_SLIP
|
||||
log_message("SLIP Driver: ", stringize(STATIC_DRIVER));
|
||||
#else /* WITH_SLIP */
|
||||
log_message("Eth. Driver: ", stringize(STATIC_DRIVER));
|
||||
#endif /* WITH_SLIP */
|
||||
log_message("Eth. Driver: ", stringize(ETHERNET));
|
||||
#undef _stringize
|
||||
#undef stringize
|
||||
#else /* STATIC_DRIVER */
|
||||
log_message("Eth. Driver: ", config.ethernet.name);
|
||||
#endif /* STATIC_DRIVER */
|
||||
#if !WITH_SLIP
|
||||
log_message("Driver Port: $", utoa(config.ethernet.addr, uip_buf, 16));
|
||||
#endif /* !WITH_SLIP */
|
||||
#endif /* !STATIC_DRIVER */
|
||||
log_message("Driver Port: $", utoa(config.ethernetcfg.addr, uip_buf, 16));
|
||||
|
||||
uip_sethostaddr(&config.hostaddr);
|
||||
uip_setnetmask(&config.netmask);
|
||||
|
@ -123,5 +107,7 @@ config_read(char *filename)
|
|||
#if WITH_DNS
|
||||
uip_nameserver_update(&config.resolvaddr, UIP_NAMESERVER_INFINITE_LIFETIME);
|
||||
#endif /* WITH_DNS */
|
||||
|
||||
return &config.ethernetcfg;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -35,22 +35,6 @@
|
|||
#ifndef CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
|
||||
extern struct {
|
||||
uip_ipaddr_t hostaddr;
|
||||
uip_ipaddr_t netmask;
|
||||
uip_ipaddr_t draddr;
|
||||
uip_ipaddr_t resolvaddr;
|
||||
union {
|
||||
struct {
|
||||
uint16_t addr;
|
||||
#ifndef STATIC_DRIVER
|
||||
char name[12+1];
|
||||
#endif /* !STATIC_DRIVER */
|
||||
} ethernet;
|
||||
uint8_t slip[5];
|
||||
};
|
||||
} config;
|
||||
|
||||
void config_read(char *filename);
|
||||
struct ethernet_config * config_read(char *filename);
|
||||
|
||||
#endif /* CONFIG_H_ */
|
||||
|
|
|
@ -92,7 +92,7 @@ PROCESS_THREAD(ethernet_process, ev, data)
|
|||
|
||||
PROCESS_BEGIN();
|
||||
|
||||
ethernet_init();
|
||||
ethernet_init((struct ethernet_config *)data);
|
||||
|
||||
tcpip_set_outputfunc(ethernet_output);
|
||||
|
||||
|
|
|
@ -35,6 +35,11 @@
|
|||
|
||||
#include "contiki.h"
|
||||
|
||||
struct ethernet_config {
|
||||
uint16_t addr;
|
||||
char name[12+1];
|
||||
};
|
||||
|
||||
PROCESS_NAME(ethernet_process);
|
||||
|
||||
#if NETSTACK_CONF_WITH_IPV6
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include "cfs/cfs.h"
|
||||
#include "sys/log.h"
|
||||
#include "lib/error.h"
|
||||
#include "lib/config.h"
|
||||
#include "net/ethernet-drv.h"
|
||||
|
||||
#include "net/ethernet.h"
|
||||
|
||||
|
@ -59,41 +59,24 @@ struct {
|
|||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ethernet_init(void)
|
||||
ethernet_init(struct ethernet_config *config)
|
||||
{
|
||||
static const char signature[4] = {0x65, 0x74, 0x68, 0x01};
|
||||
|
||||
#ifdef STATIC_DRIVER
|
||||
|
||||
extern void STATIC_DRIVER;
|
||||
|
||||
module = &STATIC_DRIVER;
|
||||
|
||||
module->buffer = uip_buf;
|
||||
module->buffer_size = UIP_BUFSIZE;
|
||||
if(module->init(config.ethernet.addr)) {
|
||||
#define _stringize(arg) #arg
|
||||
#define stringize(arg) _stringize(arg)
|
||||
log_message(stringize(STATIC_DRIVER), ": No hardware");
|
||||
#undef _stringize
|
||||
#undef stringize
|
||||
error_exit();
|
||||
}
|
||||
|
||||
#else /* STATIC_DRIVER */
|
||||
#ifndef STATIC_DRIVER
|
||||
|
||||
struct mod_ctrl module_control = {cfs_read};
|
||||
uint8_t byte;
|
||||
|
||||
module_control.callerdata = cfs_open(config.ethernet.name, CFS_READ);
|
||||
module_control.callerdata = cfs_open(config->name, CFS_READ);
|
||||
if(module_control.callerdata < 0) {
|
||||
log_message(config.ethernet.name, ": File not found");
|
||||
log_message(config->name, ": File not found");
|
||||
error_exit();
|
||||
}
|
||||
|
||||
byte = mod_load(&module_control);
|
||||
if(byte != MLOAD_OK) {
|
||||
log_message(config.ethernet.name, byte == MLOAD_ERR_MEM? ": Out of memory":
|
||||
log_message(config->name, byte == MLOAD_ERR_MEM? ": Out of memory":
|
||||
": No module");
|
||||
error_exit();
|
||||
}
|
||||
|
@ -103,20 +86,26 @@ ethernet_init(void)
|
|||
|
||||
for(byte = 0; byte < 4; ++byte) {
|
||||
if(module->signature[byte] != signature[byte]) {
|
||||
log_message(config.ethernet.name, ": No ETH driver");
|
||||
log_message(config->name, ": No ETH driver");
|
||||
error_exit();
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !STATIC_DRIVER */
|
||||
|
||||
extern void STATIC_DRIVER;
|
||||
|
||||
module = &STATIC_DRIVER;
|
||||
|
||||
#endif /* !STATIC_DRIVER */
|
||||
|
||||
module->buffer = uip_buf;
|
||||
module->buffer_size = UIP_BUFSIZE;
|
||||
if(module->init(config.ethernet.addr)) {
|
||||
log_message(config.ethernet.name, ": No hardware");
|
||||
if(module->init(config->addr)) {
|
||||
log_message(config->name, ": No hardware");
|
||||
error_exit();
|
||||
}
|
||||
|
||||
#endif /* STATIC_DRIVER */
|
||||
|
||||
uip_setethaddr(module->ethernet_address);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#ifndef ETHERNET_H_
|
||||
#define ETHERNET_H_
|
||||
|
||||
void ethernet_init(void);
|
||||
void ethernet_init(struct ethernet_config *config);
|
||||
uint16_t ethernet_poll(void);
|
||||
void ethernet_send(void);
|
||||
void ethernet_exit(void);
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
* Author: Oliver Schmidt <ol.sc@web.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <serial.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "contiki-net.h"
|
||||
#include "sys/log.h"
|
||||
#include "lib/error.h"
|
||||
#include "lib/config.h"
|
||||
|
||||
#include "dev/slip.h"
|
||||
|
||||
#if WITH_SLIP
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
slip_arch_init(unsigned long ubr)
|
||||
{
|
||||
unsigned err;
|
||||
|
||||
err = ser_install(STATIC_DRIVER);
|
||||
if(err == SER_ERR_OK) {
|
||||
err = ser_open((struct ser_params *)config.slip);
|
||||
if(err == SER_ERR_OK)
|
||||
atexit((void (*)(void))ser_close);
|
||||
}
|
||||
if(err != SER_ERR_OK) {
|
||||
err += '0';
|
||||
/* High byte of err serves as string termination. */
|
||||
log_message("Serial init error code: ", (char *)&err);
|
||||
error_exit();
|
||||
}
|
||||
|
||||
tcpip_set_outputfunc(slip_send);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
slip_arch_writeb(unsigned char c)
|
||||
{
|
||||
while(ser_put(c) == SER_ERR_OVERFLOW)
|
||||
;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
slip_arch_poll(void)
|
||||
{
|
||||
static unsigned char c;
|
||||
|
||||
while(ser_get(&c) != SER_ERR_NO_DATA)
|
||||
slip_input_byte(c);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* WITH_SLIP */
|
|
@ -1,6 +0,0 @@
|
|||
CONTIKI_PROJECT = serconfig
|
||||
all: $(CONTIKI_PROJECT)
|
||||
|
||||
CONTIKI = ../../..
|
||||
CONTIKI_WITH_IPV4 = 1
|
||||
include $(CONTIKI)/Makefile.include
|
|
@ -1 +0,0 @@
|
|||
DEFINES = WITH_PFS
|
|
@ -1 +0,0 @@
|
|||
DEFINES = WITH_PFS
|
|
@ -1,105 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <serial.h>
|
||||
|
||||
#include "cfs/cfs.h"
|
||||
|
||||
static struct {
|
||||
char *screen;
|
||||
uint8_t value;
|
||||
} baud[] = {
|
||||
{" 300 baud", SER_BAUD_300},
|
||||
{" 600 baud", SER_BAUD_600},
|
||||
{" 1200 baud", SER_BAUD_1200},
|
||||
{" 2400 baud", SER_BAUD_2400},
|
||||
{" 4800 baud", SER_BAUD_4800},
|
||||
{" 9600 baud", SER_BAUD_9600},
|
||||
{"19200 baud", SER_BAUD_19200}
|
||||
};
|
||||
|
||||
static struct {
|
||||
char *screen;
|
||||
uint8_t value;
|
||||
} stop[] = {
|
||||
{"1 stop bit", SER_STOP_1},
|
||||
{"2 stop bits", SER_STOP_2}
|
||||
};
|
||||
|
||||
static struct {
|
||||
char *screen;
|
||||
uint8_t value;
|
||||
} parity[] = {
|
||||
{" No parity", SER_PAR_NONE},
|
||||
{" Odd parity", SER_PAR_ODD},
|
||||
{"Even parity", SER_PAR_EVEN}
|
||||
};
|
||||
|
||||
uint8_t ipcfg[16];
|
||||
struct ser_params params;
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
choose(uint8_t max)
|
||||
{
|
||||
char val;
|
||||
|
||||
do {
|
||||
printf("\n?");
|
||||
val = getchar();
|
||||
} while(val < '0' || val > max + '0');
|
||||
|
||||
putchar('\n');
|
||||
if(val == '0') {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
return val - '0';
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
main(void)
|
||||
{
|
||||
int f;
|
||||
uint8_t c;
|
||||
|
||||
f = cfs_open("contiki.cfg", CFS_READ);
|
||||
if(f == -1) {
|
||||
printf("Loading Config - Error\n");
|
||||
return;
|
||||
}
|
||||
cfs_read(f, ipcfg, sizeof(ipcfg));
|
||||
cfs_close(f);
|
||||
|
||||
for(c = 0; c < sizeof(baud) / sizeof(baud[0]); ++c) {
|
||||
printf("%d: %s\n", c + 1, baud[c].screen);
|
||||
}
|
||||
params.baudrate = baud[choose(c) - 1].value;
|
||||
|
||||
params.databits = SER_BITS_8;
|
||||
|
||||
for(c = 0; c < sizeof(stop) / sizeof(stop[0]); ++c) {
|
||||
printf("%d: %s\n", c + 1, stop[c].screen);
|
||||
}
|
||||
params.stopbits = stop[choose(c) - 1].value;
|
||||
|
||||
for(c = 0; c < sizeof(parity) / sizeof(parity[0]); ++c) {
|
||||
printf("%d: %s\n", c + 1, parity[c].screen);
|
||||
}
|
||||
params.parity = parity[choose(c) - 1].value;
|
||||
|
||||
params.handshake = SER_HS_HW;
|
||||
|
||||
f = cfs_open("contiki.cfg", CFS_WRITE);
|
||||
if(f == -1) {
|
||||
printf("\nSaving Config - Error\n");
|
||||
return;
|
||||
}
|
||||
cfs_write(f, ipcfg, sizeof(ipcfg));
|
||||
cfs_write(f, ¶ms, sizeof(params));
|
||||
cfs_close(f);
|
||||
|
||||
printf("Saving Config - Done\n");
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
|
@ -12,9 +12,8 @@ CONTIKI_CPU=$(CONTIKI)/cpu/avr
|
|||
|
||||
### These directories will be searched for the specified source files
|
||||
### TARGETLIBS are platform-specific routines in the contiki library path
|
||||
CONTIKI_CPU_DIRS = . dev dev/arduino
|
||||
AVR = clock.c mtarch.c eeprom.c flash.c rs232.c leds-arch.c \
|
||||
watchdog.c rtimer-arch.c bootloader.c
|
||||
CONTIKI_CPU_DIRS = . dev
|
||||
AVR = clock.c mtarch.c eeprom.c flash.c rs232.c leds-arch.c watchdog.c rtimer-arch.c bootloader.c
|
||||
ELFLOADER = elfloader.c elfloader-avr.c symtab-avr.c
|
||||
TARGETLIBS = random.c leds.c
|
||||
|
||||
|
@ -89,7 +88,6 @@ CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES)
|
|||
|
||||
### Compiler definitions
|
||||
CC = avr-gcc
|
||||
CXX = avr-g++
|
||||
LD = avr-gcc
|
||||
AS = avr-as
|
||||
AR = avr-ar
|
||||
|
@ -131,12 +129,6 @@ $(OBJECTDIR)/%.o: %.c | $(OBJECTDIR)
|
|||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJECTDIR)/%.o: %.cpp | $(OBJECTDIR)
|
||||
$(CXX) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.ko: %.o
|
||||
$(STRIP) -K _init -K _fini --strip-unneeded -g -x $< -o $@
|
||||
|
||||
|
@ -202,18 +194,22 @@ endif
|
|||
### Upload image
|
||||
#Let avrdude use defaults if port or programmer not defined
|
||||
AVRDUDE ?= avrdude
|
||||
ifdef AVRDUDE_PORT
|
||||
AVRDUDE_PORT:=-P $(AVRDUDE_PORT)
|
||||
endif
|
||||
ifdef AVRDUDE_PROGRAMMER
|
||||
AVRDUDE_PROGRAMMER:=-c $(AVRDUDE_PROGRAMMER)
|
||||
endif
|
||||
ifdef AVRDUDE_MCU
|
||||
DUDE_MCU:=-p $(AVRDUDE_MCU)
|
||||
AVRDUDE_MCU:=-p $(AVRDUDE_MCU)
|
||||
else
|
||||
DUDE_MCU:=-p $(MCU)
|
||||
AVRDUDE_MCU:=-p $(MCU)
|
||||
endif
|
||||
%.u: %.hex
|
||||
$(AVRDUDE) $(DUDE_MCU) $(AVRDUDE_OPTIONS) -P $(AVRDUDE_PORT) \
|
||||
-c $(AVRDUDE_PROGRAMMER) -U flash:w:$<:i
|
||||
$(AVRDUDE) $(AVRDUDE_MCU) $(AVRDUDE_OPTIONS) $(AVRDUDE_PORT) $(AVRDUDE_PROGRAMMER) -U flash:w:$<
|
||||
|
||||
%.eu: %.eep
|
||||
$(AVRDUDE) $(DUDE_MCU) ${AVRDUDE_OPTIONS} -P ${AVRDUDE_PORT} \
|
||||
-c ${AVRDUDE_PROGRAMMER} -U eeprom:w:$<:i
|
||||
$(AVRDUDE) $(AVRDUDE_MCU) ${AVRDUDE_OPTIONS} ${AVRDUDE_PORT} ${AVRDUDE_PROGRAMMER} -U eeprom:w:$<
|
||||
|
||||
symbols.c:
|
||||
cp ${CONTIKI}/tools/empty-symbols.c symbols.c
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012, BinaryLabs.
|
||||
* 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.
|
||||
*
|
||||
* @(#)$Id: adc.c,v 1.1 2010/08/25 19:34:06 nifi Exp $
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* ADC file for Atmega128rfa1.
|
||||
* \author
|
||||
* Paulo Louro <paulolouro@binarylabs.dk>
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
|
||||
static uint8_t analog_reference = ADC_DEFAULT;
|
||||
|
||||
/*
|
||||
* For arduino interface for setting external reference voltage
|
||||
* Note that applying an external voltage *and* then setting the analog
|
||||
* reference to something internal will short the internal and the
|
||||
* external reference voltage and most likely destroy the processor.
|
||||
*/
|
||||
void analogReference(uint8_t mode)
|
||||
{
|
||||
analog_reference = mode;
|
||||
}
|
||||
|
||||
int readADC(uint8_t pin)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
adc_setup (analog_reference, pin);
|
||||
result = adc_read ();
|
||||
adc_fin ();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return Internal temperature in 0.01C, e.g. 25C is 2500
|
||||
*/
|
||||
int readInternalTemp(void)
|
||||
{
|
||||
int reading = 0;
|
||||
|
||||
ADCSRB |= _BV(MUX5);
|
||||
ADMUX = _BV(REFS1) | _BV(REFS0) | 0b1001 ;
|
||||
ADCSRA = _BV(ADEN) | _BV(ADPS0) | _BV(ADPS2) ;
|
||||
|
||||
ADCSRA |= 1 << ADSC;
|
||||
loop_until_bit_is_clear(ADCSRA,ADSC);
|
||||
reading = ADC;
|
||||
|
||||
ADCSRB=0; //disable ADC, need to write B first for MUX5 bit
|
||||
ADCSRA=0; //disable ADC
|
||||
ADMUX=0; //turn off internal vref
|
||||
|
||||
return reading * 113 - 27280;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
#ifndef __ADC_ARCH_H__
|
||||
#define __ADC_ARCH_H__
|
||||
|
||||
#include <avr/io.h>
|
||||
|
||||
/*
|
||||
* Reference voltage
|
||||
* The default is 1.6V reference voltage
|
||||
* The selected reference voltage is the maximum voltage that can be
|
||||
* measured.
|
||||
* Directly provide shifted variants so we don't need to shift.
|
||||
*/
|
||||
#define ADC_1_5 (2<<6)
|
||||
#define ADC_1_6 (3<<6)
|
||||
#define ADC_1_8 (1<<6)
|
||||
#define ADC_EXTERNAL (0<<6)
|
||||
#define ADC_DEFAULT ADC_1_6
|
||||
|
||||
/* sometimes it's desirable to decouple setup / finish from sampling */
|
||||
|
||||
static inline void adc_setup (uint8_t ref_volt, uint8_t pin)
|
||||
{
|
||||
ADMUX = ref_volt | (pin & 0x7);
|
||||
ADCSRA = _BV(ADEN) | _BV(ADPS0) | _BV(ADPS2);
|
||||
}
|
||||
|
||||
static inline int adc_read (void)
|
||||
{
|
||||
ADCSRA |= (1 << ADSC);
|
||||
loop_until_bit_is_clear (ADCSRA, ADSC);
|
||||
return ADC;
|
||||
}
|
||||
|
||||
static inline void adc_fin (void)
|
||||
{
|
||||
ADCSRA = 0;
|
||||
ADMUX = 0;
|
||||
}
|
||||
|
||||
static inline void adc_init (void)
|
||||
{
|
||||
uint8_t temp;
|
||||
ADCSRC = 0;
|
||||
ADCSRB = 0;
|
||||
adc_fin ();
|
||||
/*
|
||||
* Disable JTAG interface
|
||||
* Hardware manual about JTD bit:
|
||||
* "In order to avoid unintentional disabling or enabling of the
|
||||
* JTAG interface, a timed sequence must be followed when changing
|
||||
* this bit: The application software must write this bit to the
|
||||
* desired value twice within four cycles to change its value."
|
||||
* 15.4.1 "MCUCR - MCU Control Register", p. 219
|
||||
*/
|
||||
temp = MCUCR | (1 << JTD);
|
||||
MCUCR = temp;
|
||||
MCUCR = temp;
|
||||
}
|
||||
|
||||
int readADC(uint8_t pin);
|
||||
long readVcc();
|
||||
int readInternalTemp(void);
|
||||
void analogReference(uint8_t mode);
|
||||
|
||||
#endif /* __ADC_ARCH_H__ */
|
|
@ -1,174 +0,0 @@
|
|||
#ifndef Arduino_h
|
||||
#define Arduino_h
|
||||
|
||||
#include <hw-arduino.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "binary.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#define HIGH 0x1
|
||||
#define LOW 0x0
|
||||
|
||||
#define INPUT 0x0
|
||||
#define OUTPUT 0x1
|
||||
#define INPUT_PULLUP 0x2
|
||||
|
||||
#define true 0x1
|
||||
#define false 0x0
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
|
||||
#define SERIAL 0x0
|
||||
#define DISPLAY 0x1
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
#define CHANGE 1
|
||||
#define FALLING 2
|
||||
#define RISING 3
|
||||
|
||||
#define DEFAULT ADC_DEFAULT
|
||||
#define EXTERNAL ADC_EXTERNAL
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
|
||||
#define interrupts() sei()
|
||||
#define noInterrupts() cli()
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define microsecondsToClockCycles(a) ( (a) * (F_CPU / 1000000L) )
|
||||
|
||||
typedef unsigned int word;
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef uint8_t boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
void pinMode(uint8_t, uint8_t);
|
||||
void digitalWrite(uint8_t, uint8_t);
|
||||
int digitalRead(uint8_t);
|
||||
|
||||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
|
||||
|
||||
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
|
||||
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
|
||||
|
||||
void attachInterrupt(uint8_t, void (*)(void), int mode);
|
||||
void detachInterrupt(uint8_t);
|
||||
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
||||
// Get the bit location within the hardware port of the given virtual pin.
|
||||
// This comes from the pins_*.c file for the active board configuration.
|
||||
|
||||
#define analogInPinToBit(P) (P)
|
||||
|
||||
// On the ATmega1280, the addresses of some of the port registers are
|
||||
// greater than 255, so we can't store them in uint8_t's.
|
||||
extern const uint16_t PROGMEM port_to_mode_PGM[];
|
||||
extern const uint16_t PROGMEM port_to_input_PGM[];
|
||||
extern const uint16_t PROGMEM port_to_output_PGM[];
|
||||
|
||||
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
|
||||
// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
|
||||
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
|
||||
|
||||
// Get the bit location within the hardware port of the given virtual pin.
|
||||
// This comes from the pins_*.c file for the active board configuration.
|
||||
//
|
||||
// These perform slightly better as macros compared to inline functions
|
||||
//
|
||||
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
|
||||
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
|
||||
#define analogInPinToBit(P) (P)
|
||||
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
|
||||
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
|
||||
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
|
||||
|
||||
#define NOT_A_PIN 0
|
||||
#define NOT_A_PORT 0
|
||||
|
||||
#ifdef ARDUINO_MAIN
|
||||
#define PA 1
|
||||
#define PB 2
|
||||
#define PC 3
|
||||
#define PD 4
|
||||
#define PE 5
|
||||
#define PF 6
|
||||
#define PG 7
|
||||
#define PH 8
|
||||
#define PJ 10
|
||||
#define PK 11
|
||||
#define PL 12
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
// look at this again when considering implementing serial
|
||||
#include "WCharacter.h"
|
||||
#include "WString.h"
|
||||
#include "HardwareSerial.h"
|
||||
|
||||
uint16_t makeWord(uint16_t w);
|
||||
uint16_t makeWord(byte h, byte l);
|
||||
|
||||
#define word(...) makeWord(__VA_ARGS__)
|
||||
|
||||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
|
||||
|
||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
|
||||
void noTone(uint8_t _pin);
|
||||
|
||||
// WMath prototypes
|
||||
long random(long);
|
||||
long random(long, long);
|
||||
void randomSeed(unsigned int);
|
||||
long map(long, long, long, long, long);
|
||||
|
||||
#endif
|
||||
|
||||
#include "pins_arduino.h"
|
||||
|
||||
#include "dev/arduino/arduino-compat.h"
|
||||
|
||||
#endif
|
|
@ -1,146 +0,0 @@
|
|||
/*
|
||||
EEPROM.h - EEPROM library
|
||||
Original Copyright (c) 2006 David A. Mellis. All right reserved.
|
||||
New version by Christopher Andrews 2015.
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#ifndef EEPROM_h
|
||||
#define EEPROM_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
/***
|
||||
EERef class.
|
||||
|
||||
This object references an EEPROM cell.
|
||||
Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM.
|
||||
This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell.
|
||||
***/
|
||||
|
||||
struct EERef{
|
||||
|
||||
EERef( const int index )
|
||||
: index( index ) {}
|
||||
|
||||
//Access/read members.
|
||||
uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); }
|
||||
operator const uint8_t() const { return **this; }
|
||||
|
||||
//Assignment/write members.
|
||||
EERef &operator=( const EERef &ref ) { return *this = *ref; }
|
||||
EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; }
|
||||
EERef &operator +=( uint8_t in ) { return *this = **this + in; }
|
||||
EERef &operator -=( uint8_t in ) { return *this = **this - in; }
|
||||
EERef &operator *=( uint8_t in ) { return *this = **this * in; }
|
||||
EERef &operator /=( uint8_t in ) { return *this = **this / in; }
|
||||
EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; }
|
||||
EERef &operator %=( uint8_t in ) { return *this = **this % in; }
|
||||
EERef &operator &=( uint8_t in ) { return *this = **this & in; }
|
||||
EERef &operator |=( uint8_t in ) { return *this = **this | in; }
|
||||
EERef &operator <<=( uint8_t in ) { return *this = **this << in; }
|
||||
EERef &operator >>=( uint8_t in ) { return *this = **this >> in; }
|
||||
|
||||
EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; }
|
||||
|
||||
/** Prefix increment/decrement **/
|
||||
EERef& operator++() { return *this += 1; }
|
||||
EERef& operator--() { return *this -= 1; }
|
||||
|
||||
/** Postfix increment/decrement **/
|
||||
uint8_t operator++ (int){
|
||||
uint8_t ret = **this;
|
||||
return ++(*this), ret;
|
||||
}
|
||||
|
||||
uint8_t operator-- (int){
|
||||
uint8_t ret = **this;
|
||||
return --(*this), ret;
|
||||
}
|
||||
|
||||
int index; //Index of current EEPROM cell.
|
||||
};
|
||||
|
||||
/***
|
||||
EEPtr class.
|
||||
|
||||
This object is a bidirectional pointer to EEPROM cells represented by EERef objects.
|
||||
Just like a normal pointer type, this can be dereferenced and repositioned using
|
||||
increment/decrement operators.
|
||||
***/
|
||||
|
||||
struct EEPtr{
|
||||
|
||||
EEPtr( const int index )
|
||||
: index( index ) {}
|
||||
|
||||
operator const int() const { return index; }
|
||||
EEPtr &operator=( int in ) { return index = in, *this; }
|
||||
|
||||
//Iterator functionality.
|
||||
bool operator!=( const EEPtr &ptr ) { return index != ptr.index; }
|
||||
EERef operator*() { return index; }
|
||||
|
||||
/** Prefix & Postfix increment/decrement **/
|
||||
EEPtr& operator++() { return ++index, *this; }
|
||||
EEPtr& operator--() { return --index, *this; }
|
||||
EEPtr operator++ (int) { return index++; }
|
||||
EEPtr operator-- (int) { return index--; }
|
||||
|
||||
int index; //Index of current EEPROM cell.
|
||||
};
|
||||
|
||||
/***
|
||||
EEPROMClass class.
|
||||
|
||||
This object represents the entire EEPROM space.
|
||||
It wraps the functionality of EEPtr and EERef into a basic interface.
|
||||
This class is also 100% backwards compatible with earlier Arduino core releases.
|
||||
***/
|
||||
|
||||
struct EEPROMClass{
|
||||
|
||||
//Basic user access methods.
|
||||
EERef operator[]( const int idx ) { return idx; }
|
||||
uint8_t read( int idx ) { return EERef( idx ); }
|
||||
void write( int idx, uint8_t val ) { (EERef( idx )) = val; }
|
||||
void update( int idx, uint8_t val ) { EERef( idx ).update( val ); }
|
||||
|
||||
//STL and C++11 iteration capability.
|
||||
EEPtr begin() { return 0x00; }
|
||||
EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid.
|
||||
uint16_t length() { return E2END + 1; }
|
||||
|
||||
//Functionality to 'get' and 'put' objects to and from EEPROM.
|
||||
template< typename T > T &get( int idx, T &t ){
|
||||
EEPtr e = idx;
|
||||
uint8_t *ptr = (uint8_t*) &t;
|
||||
for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e;
|
||||
return t;
|
||||
}
|
||||
|
||||
template< typename T > const T &put( int idx, const T &t ){
|
||||
EEPtr e = idx;
|
||||
const uint8_t *ptr = (const uint8_t*) &t;
|
||||
for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ );
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
static EEPROMClass EEPROM;
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue