Compare commits

..

No commits in common. "master" and "master-31012017" have entirely different histories.

1385 changed files with 4762 additions and 156862 deletions

7
.gitmodules vendored
View file

@ -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

View file

@ -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
View file

@ -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.

View file

@ -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)}}
@ -156,18 +156,16 @@ endif
### Verbosity control. Use make V=1 to get verbose builds.
ifeq ($(V),1)
TRACE_CC =
TRACE_CXX =
TRACE_LD =
TRACE_AR =
TRACE_AS =
TRACE_CC =
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 " $<
TRACE_CC = @echo " CC " $<
TRACE_LD = @echo " LD " $@
TRACE_AR = @echo " AR " $@
TRACE_AS = @echo " AS " $<
Q=@
endif
@ -186,9 +184,8 @@ CONTIKI_CPU_DIRS_CONCAT = ${addprefix $(CONTIKI_CPU)/, \
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)
vpath %.c $(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.

View file

@ -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.

View file

@ -1,2 +0,0 @@
arduino_src = arduino-process.c

View file

@ -1,4 +0,0 @@
%.cpp: %.pde
echo '#include "Arduino.h"' > $@
echo '#include "$<"' >> $@

View file

@ -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).

View file

@ -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
*/
/** @} */

View file

@ -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
*/
/** @} */

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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;
@ -257,12 +256,12 @@ coap_receive()
transaction = NULL;
#if COAP_OBSERVE_CLIENT
/* if observe notification */
/* if observe notification */
if((message->type == COAP_TYPE_CON || message->type == COAP_TYPE_NON)
&& IS_OPTION(message, COAP_OPTION_OBSERVE)) {
&& IS_OPTION(message, COAP_OPTION_OBSERVE)) {
PRINTF("Observe [%u]\n", message->observe);
coap_handle_notification(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport,
message);
message);
}
#endif /* COAP_OBSERVE_CLIENT */
} /* request or response */
@ -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,

View file

@ -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 -------------------------------------------------------------*/

View file

@ -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,

View file

@ -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)) {
@ -276,10 +274,8 @@ coap_observe_handler(resource_t *resource, void *request, void *response)
obs = add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport,
coap_req->token, coap_req->token_len,
coap_req->uri_path, coap_req->uri_path_len);
if(obs) {
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.

View file

@ -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();
}

View file

@ -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;
@ -178,7 +178,7 @@ coap_serialize_array_option(unsigned int number, unsigned int current_number,
size_t i = 0;
PRINTF("ARRAY type %u, len %zu, full [%.*s]\n", number, length,
(int)length, array);
(int)length, array);
if(split_char != '\0') {
int j;
@ -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);
@ -596,7 +602,7 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
coap_pkt->uri_host = (char *)current_option;
coap_pkt->uri_host_len = option_length;
PRINTF("Uri-Host [%.*s]\n", (int)coap_pkt->uri_host_len,
coap_pkt->uri_host);
coap_pkt->uri_host);
break;
case COAP_OPTION_URI_PORT:
coap_pkt->uri_port = coap_parse_int_option(current_option,

View file

@ -61,8 +61,8 @@
(REST_MAX_CHUNK_SIZE < 128 ? 64 : \
(REST_MAX_CHUNK_SIZE < 256 ? 128 : \
(REST_MAX_CHUNK_SIZE < 512 ? 256 : \
(REST_MAX_CHUNK_SIZE < 1024 ? 512 : \
(REST_MAX_CHUNK_SIZE < 2048 ? 1024 : 2048)))))))
(REST_MAX_CHUNK_SIZE < 1024 ? 512 : \
(REST_MAX_CHUNK_SIZE < 2048 ? 1024 : 2048)))))))
#endif /* COAP_MAX_BLOCK_SIZE */
/* direct access into the buffer */
@ -135,7 +135,7 @@ typedef struct {
/* option format serialization */
#define COAP_SERIALIZE_INT_OPTION(number, field, text) \
if(IS_OPTION(coap_pkt, number)) { \
PRINTF(text " [%u]\n", (unsigned int)coap_pkt->field); \
PRINTF(text " [%u]\n", (unsigned int)coap_pkt->field); \
option += coap_serialize_int_option(number, current_number, option, coap_pkt->field); \
current_number = number; \
}
@ -167,7 +167,7 @@ typedef struct {
uint32_t block = coap_pkt->field##_num << 4; \
if(coap_pkt->field##_more) { block |= 0x8; } \
block |= 0xF & coap_log_2(coap_pkt->field##_size / 16); \
PRINTF(text " encoded: 0x%lX\n", (unsigned long)block); \
PRINTF(text " encoded: 0x%lX\n", (unsigned long)block); \
option += coap_serialize_int_option(number, current_number, option, block); \
current_number = number; \
}

View file

@ -1 +0,0 @@
json-resource_src = generic_resource.c

View file

@ -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
*/
/** @} */

View file

@ -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
*/
/** @} */

View file

@ -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,18 +147,14 @@ typedef enum {
*/
#define PT_MQTT_WAIT_SEND() \
do { \
if (PROCESS_ERR_OK == \
process_post(PROCESS_CURRENT(), mqtt_continue_send_event, NULL)) { \
do { \
PROCESS_WAIT_EVENT(); \
if(ev == mqtt_abort_now_event) { \
conn->state = MQTT_CONN_STATE_ABORT_IMMEDIATE; \
PT_INIT(&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); \
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_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(0)
/*---------------------------------------------------------------------------*/
@ -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);

View file

@ -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 {

View file

@ -1 +0,0 @@
ota-update_src = res_bootloader.c res_reboot.c res_upload_image.c

View file

@ -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");

View file

@ -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
);

View file

@ -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
);

View file

@ -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
);

View file

@ -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 */

View file

@ -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));
}

View file

@ -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

View file

@ -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);
}
/*---------------------------------------------------------------------------*/

View file

@ -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_ */

View file

@ -1,2 +0,0 @@
time_src = time.c resource_gmtime.c resource_timestamp.c \
resource_timezone.c resource_crontab.c cron.c

View file

@ -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

View file

@ -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; \
}

View file

@ -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;
}
}
}

View file

@ -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_ */

View file

@ -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
*/

View file

@ -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
*/

View file

@ -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
*/

View file

@ -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
*/

View file

@ -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;
}
/** @} */

View file

@ -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
/** @} */

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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];

View file

@ -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) {
/*

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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

View file

@ -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;
}
/*---------------------------------------------------------------------------*/

View file

@ -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 */

View file

@ -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) {

View file

@ -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:

View file

@ -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 {

View file

@ -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.
*/

View file

@ -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));

View 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]));
}
}
ip64_addr_4to6((uip_ip4addr_t *)&s->dnsaddr, &ip6dnsaddr);
// mdns_conf(&ip6dnsaddr);
}
/*---------------------------------------------------------------------------*/
void

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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 */

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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");
}
}
}
@ -642,18 +642,12 @@ rpl_update_header(void)
if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
/* At the root, remove headers if any, and insert SRH or HBH
* (SRH is inserted only if the destination is in the DODAG) */
* (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);
}
if(RPL_IS_NON_STORING(default_instance)) {
return insert_srh_header();
} else {
/* dest is outside of DODAGs; no ext header is needed. */
return 1;
return insert_hbh_header(default_instance);
}
} else {
if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)

View file

@ -79,7 +79,7 @@ static void dao_input(void);
static void dao_ack_input(void);
static void dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
uint8_t lifetime, uint8_t seq_no);
uint8_t lifetime, uint8_t seq_no);
/* some debug callbacks useful when debugging RPL networks */
#ifdef RPL_DEBUG_DIO_INPUT
@ -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,15 +218,16 @@ 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
PRINTF("RPL: LEAF ONLY Multicast DIS will NOT reset DIO timer\n");
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 {
/* Check if this neighbor should be added according to the policy. */
#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) {
PRINTF("RPL: Out of Memory, not sending unicast DIO, DIS from ");
@ -238,7 +239,7 @@ dis_input(void)
PRINTF("RPL: Unicast DIS, reply to sender\n");
dio_output(instance, &UIP_IP_BUF->srcipaddr);
}
/* } */
/* } */
}
}
}
@ -355,103 +356,103 @@ dio_input(void)
PRINTF("RPL: DIO option %u, length: %u\n", subopt_type, len - 2);
switch(subopt_type) {
case RPL_OPTION_DAG_METRIC_CONTAINER:
if(len < 6) {
PRINTF("RPL: Invalid DAG MC, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
dio.mc.type = buffer[i + 2];
dio.mc.flags = buffer[i + 3] << 1;
dio.mc.flags |= buffer[i + 4] >> 7;
dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3;
dio.mc.prec = buffer[i + 4] & 0xf;
dio.mc.length = buffer[i + 5];
case RPL_OPTION_DAG_METRIC_CONTAINER:
if(len < 6) {
PRINTF("RPL: Invalid DAG MC, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
dio.mc.type = buffer[i + 2];
dio.mc.flags = buffer[i + 3] << 1;
dio.mc.flags |= buffer[i + 4] >> 7;
dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3;
dio.mc.prec = buffer[i + 4] & 0xf;
dio.mc.length = buffer[i + 5];
if(dio.mc.type == RPL_DAG_MC_NONE) {
/* No metric container: do nothing */
} else if(dio.mc.type == RPL_DAG_MC_ETX) {
dio.mc.obj.etx = get16(buffer, i + 6);
if(dio.mc.type == RPL_DAG_MC_NONE) {
/* No metric container: do nothing */
} else if(dio.mc.type == RPL_DAG_MC_ETX) {
dio.mc.obj.etx = get16(buffer, i + 6);
PRINTF("RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n",
(unsigned)dio.mc.type,
(unsigned)dio.mc.flags,
(unsigned)dio.mc.aggr,
(unsigned)dio.mc.prec,
(unsigned)dio.mc.length,
(unsigned)dio.mc.obj.etx);
} else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
dio.mc.obj.energy.flags = buffer[i + 6];
dio.mc.obj.energy.energy_est = buffer[i + 7];
} else {
PRINTF("RPL: Unhandled DAG MC type: %u\n", (unsigned)dio.mc.type);
goto discard;
}
break;
case RPL_OPTION_ROUTE_INFO:
if(len < 9) {
PRINTF("RPL: Invalid destination prefix option, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
PRINTF("RPL: DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n",
(unsigned)dio.mc.type,
(unsigned)dio.mc.flags,
(unsigned)dio.mc.aggr,
(unsigned)dio.mc.prec,
(unsigned)dio.mc.length,
(unsigned)dio.mc.obj.etx);
} else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
dio.mc.obj.energy.flags = buffer[i + 6];
dio.mc.obj.energy.energy_est = buffer[i + 7];
} else {
PRINTF("RPL: Unhandled DAG MC type: %u\n", (unsigned)dio.mc.type);
goto discard;
}
break;
case RPL_OPTION_ROUTE_INFO:
if(len < 9) {
PRINTF("RPL: Invalid destination prefix option, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
/* The flags field includes the preference value. */
dio.destination_prefix.length = buffer[i + 2];
dio.destination_prefix.flags = buffer[i + 3];
dio.destination_prefix.lifetime = get32(buffer, i + 4);
/* The flags field includes the preference value. */
dio.destination_prefix.length = buffer[i + 2];
dio.destination_prefix.flags = buffer[i + 3];
dio.destination_prefix.lifetime = get32(buffer, i + 4);
if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
dio.destination_prefix.length <= 128) {
PRINTF("RPL: Copying destination prefix\n");
memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
(dio.destination_prefix.length + 7) / 8);
} else {
PRINTF("RPL: Invalid route info option, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
dio.destination_prefix.length <= 128) {
PRINTF("RPL: Copying destination prefix\n");
memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
(dio.destination_prefix.length + 7) / 8);
} else {
PRINTF("RPL: Invalid route info option, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
break;
case RPL_OPTION_DAG_CONF:
if(len != 16) {
PRINTF("RPL: Invalid DAG configuration option, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
break;
case RPL_OPTION_DAG_CONF:
if(len != 16) {
PRINTF("RPL: Invalid DAG configuration option, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
/* Path control field not yet implemented - at i + 2 */
dio.dag_intdoubl = buffer[i + 3];
dio.dag_intmin = buffer[i + 4];
dio.dag_redund = buffer[i + 5];
dio.dag_max_rankinc = get16(buffer, i + 6);
dio.dag_min_hoprankinc = get16(buffer, i + 8);
dio.ocp = get16(buffer, i + 10);
/* buffer + 12 is reserved */
dio.default_lifetime = buffer[i + 13];
dio.lifetime_unit = get16(buffer, i + 14);
PRINTF("RPL: DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n",
dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
dio.default_lifetime, dio.lifetime_unit);
break;
case RPL_OPTION_PREFIX_INFO:
if(len != 32) {
PRINTF("RPL: Invalid DAG prefix info, len != 32\n");
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
dio.prefix_info.length = buffer[i + 2];
dio.prefix_info.flags = buffer[i + 3];
/* valid lifetime is ingnored for now - at i + 4 */
/* preferred lifetime stored in lifetime */
dio.prefix_info.lifetime = get32(buffer, i + 8);
/* 32-bit reserved at i + 12 */
PRINTF("RPL: Copying prefix information\n");
memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
break;
default:
PRINTF("RPL: Unsupported suboption type in DIO: %u\n",
(unsigned)subopt_type);
/* Path control field not yet implemented - at i + 2 */
dio.dag_intdoubl = buffer[i + 3];
dio.dag_intmin = buffer[i + 4];
dio.dag_redund = buffer[i + 5];
dio.dag_max_rankinc = get16(buffer, i + 6);
dio.dag_min_hoprankinc = get16(buffer, i + 8);
dio.ocp = get16(buffer, i + 10);
/* buffer + 12 is reserved */
dio.default_lifetime = buffer[i + 13];
dio.lifetime_unit = get16(buffer, i + 14);
PRINTF("RPL: DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n",
dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
dio.default_lifetime, dio.lifetime_unit);
break;
case RPL_OPTION_PREFIX_INFO:
if(len != 32) {
PRINTF("RPL: Invalid DAG prefix info, len != 32\n");
RPL_STAT(rpl_stats.malformed_msgs++);
goto discard;
}
dio.prefix_info.length = buffer[i + 2];
dio.prefix_info.flags = buffer[i + 3];
/* valid lifetime is ingnored for now - at i + 4 */
/* preferred lifetime stored in lifetime */
dio.prefix_info.lifetime = get32(buffer, i + 8);
/* 32-bit reserved at i + 12 */
PRINTF("RPL: Copying prefix information\n");
memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
break;
default:
PRINTF("RPL: Unsupported suboption type in DIO: %u\n",
(unsigned)subopt_type);
}
}
@ -461,7 +462,7 @@ dio_input(void)
rpl_process_dio(&from, &dio);
discard:
discard:
uip_clear_buf();
}
/*---------------------------------------------------------------------------*/
@ -546,7 +547,7 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
buffer[pos++] = instance->mc.obj.energy.energy_est;
} else {
PRINTF("RPL: Unable to send DIO because of unhandled DAG MC type %u\n",
(unsigned)instance->mc.type);
(unsigned)instance->mc.type);
return;
}
}
@ -600,7 +601,7 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
}
#endif /* DEBUG_PRINT */
PRINTF("RPL: Sending unicast-DIO with rank %u to ",
(unsigned)dag->rank);
(unsigned)dag->rank);
PRINT6ADDR(uc_addr);
PRINTF("\n");
uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos);
@ -608,12 +609,12 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
/* Unicast requests get unicast replies! */
if(uc_addr == NULL) {
PRINTF("RPL: Sending a multicast-DIO with rank %u\n",
(unsigned)instance->current_dag->rank);
(unsigned)instance->current_dag->rank);
uip_create_linklocal_rplnodes_mcast(&addr);
uip_icmp6_send(&addr, ICMP6_RPL, RPL_CODE_DIO, pos);
} else {
PRINTF("RPL: Sending unicast-DIO with rank %u to ",
(unsigned)instance->current_dag->rank);
(unsigned)instance->current_dag->rank);
PRINT6ADDR(uc_addr);
PRINTF("\n");
uip_icmp6_send(uc_addr, ICMP6_RPL, RPL_CODE_DIO, pos);
@ -636,8 +637,8 @@ dao_input_storing(void)
uint8_t flags;
uint8_t subopt_type;
/*
uint8_t pathcontrol;
uint8_t pathsequence;
uint8_t pathcontrol;
uint8_t pathsequence;
*/
uip_ipaddr_t prefix;
uip_ds6_route_t *rep;
@ -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);
@ -684,11 +684,11 @@ dao_input_storing(void)
}
learned_from = uip_is_addr_mcast(&dao_sender_addr) ?
RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO;
RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO;
/* Destination Advertisement Object */
PRINTF("RPL: Received a (%s) DAO with sequence number %u from ",
learned_from == RPL_ROUTE_FROM_UNICAST_DAO? "unicast": "multicast", sequence);
learned_from == RPL_ROUTE_FROM_UNICAST_DAO? "unicast": "multicast", sequence);
PRINT6ADDR(&dao_sender_addr);
PRINTF("\n");
@ -700,7 +700,7 @@ dao_input_storing(void)
if(parent != NULL &&
DAG_RANK(parent->rank, instance) < DAG_RANK(dag->rank, instance)) {
PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n",
DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
parent->rank = INFINITE_RANK;
parent->flags |= RPL_PARENT_FLAG_UPDATED;
return;
@ -726,34 +726,29 @@ dao_input_storing(void)
}
switch(subopt_type) {
case RPL_OPTION_TARGET:
/* Handle the target option. */
prefixlen = buffer[i + 3];
memset(&prefix, 0, sizeof(prefix));
memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
break;
case RPL_OPTION_TRANSIT:
/* The path sequence and control are ignored. */
/* pathcontrol = buffer[i + 3];
pathsequence = buffer[i + 4];*/
lifetime = buffer[i + 5];
/* The parent address is also ignored. */
break;
case RPL_OPTION_TARGET:
/* Handle the target option. */
prefixlen = buffer[i + 3];
memset(&prefix, 0, sizeof(prefix));
memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
break;
case RPL_OPTION_TRANSIT:
/* The path sequence and control are ignored. */
/* pathcontrol = buffer[i + 3];
pathsequence = buffer[i + 4];*/
lifetime = buffer[i + 5];
/* The parent address is also ignored. */
break;
}
}
PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ",
(unsigned)lifetime, (unsigned)prefixlen);
(unsigned)lifetime, (unsigned)prefixlen);
PRINT6ADDR(&prefix);
PRINTF("\n");
#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;
@ -787,7 +782,7 @@ dao_input_storing(void)
out_seq = prepare_for_dao_fwd(sequence, rep);
PRINTF("RPL: Forwarding No-path DAO to parent - out_seq:%d",
out_seq);
out_seq);
PRINT6ADDR(rpl_get_parent_ipaddr(dag->preferred_parent));
PRINTF("\n");
@ -819,8 +814,8 @@ dao_input_storing(void)
if(flags & RPL_DAO_K_FLAG) {
/* signal the failure to add the node */
dao_ack_output(instance, &dao_sender_addr, sequence,
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
}
return;
}
@ -832,8 +827,8 @@ dao_input_storing(void)
if(flags & RPL_DAO_K_FLAG) {
/* signal the failure to add the node */
dao_ack_output(instance, &dao_sender_addr, sequence,
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
}
return;
}
@ -850,33 +845,29 @@ 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.
* (e.g. the route is installed already so it will not take any
* more room that it already takes - so should be ok!)
*/
if((!RPL_ROUTE_IS_DAO_PENDING(rep) &&
rep->state.dao_seqno_in == sequence) ||
dag->rank == ROOT_RANK(instance)) {
should_ack = 1;
}
/*
* check if this route is already installed and we can ack now!
* not pending - and same seq-no means that we can ack.
* (e.g. the route is installed already so it will not take any
* more room that it already takes - so should be ok!)
*/
if((!RPL_ROUTE_IS_DAO_PENDING(rep) &&
rep->state.dao_seqno_in == sequence) ||
dag->rank == ROOT_RANK(instance)) {
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) {
/* keep the same seq-no as before for parent also */
out_seq = rep->state.dao_seqno_out;
} else {
out_seq = prepare_for_dao_fwd(sequence, rep);
}
/* 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) {
/* keep the same seq-no as before for parent also */
out_seq = rep->state.dao_seqno_out;
} else {
out_seq = prepare_for_dao_fwd(sequence, rep);
}
PRINTF("RPL: Forwarding DAO to parent ");
@ -958,26 +949,26 @@ dao_input_nonstoring(void)
}
switch(subopt_type) {
case RPL_OPTION_TARGET:
/* Handle the target option. */
prefixlen = buffer[i + 3];
memset(&prefix, 0, sizeof(prefix));
memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
break;
case RPL_OPTION_TRANSIT:
/* The path sequence and control are ignored. */
/* pathcontrol = buffer[i + 3];
pathsequence = buffer[i + 4];*/
lifetime = buffer[i + 5];
if(len >= 20) {
memcpy(&dao_parent_addr, buffer + i + 6, 16);
}
break;
case RPL_OPTION_TARGET:
/* Handle the target option. */
prefixlen = buffer[i + 3];
memset(&prefix, 0, sizeof(prefix));
memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
break;
case RPL_OPTION_TRANSIT:
/* The path sequence and control are ignored. */
/* pathcontrol = buffer[i + 3];
pathsequence = buffer[i + 4];*/
lifetime = buffer[i + 5];
if(len >= 20) {
memcpy(&dao_parent_addr, buffer + i + 6, 16);
}
break;
}
}
PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ",
(unsigned)lifetime, (unsigned)prefixlen);
(unsigned)lifetime, (unsigned)prefixlen);
PRINT6ADDR(&prefix);
PRINTF(", parent: ");
PRINT6ADDR(&dao_parent_addr);
@ -997,7 +988,7 @@ dao_input_nonstoring(void)
PRINTF("RPL: Sending DAO ACK\n");
uip_clear_buf();
dao_ack_output(instance, &dao_sender_addr, sequence,
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
}
#endif /* RPL_WITH_NON_STORING */
}
@ -1027,7 +1018,7 @@ dao_input(void)
dao_input_nonstoring();
}
discard:
discard:
uip_clear_buf();
}
/*---------------------------------------------------------------------------*/
@ -1069,7 +1060,7 @@ handle_dao_retransmission(void *ptr)
}
PRINTF("RPL: will retransmit DAO - seq:%d trans:%d\n", instance->my_dao_seqno,
instance->my_dao_transmissions);
instance->my_dao_transmissions);
if(get_global_addr(&prefix) == 0) {
return;
@ -1078,11 +1069,11 @@ handle_dao_retransmission(void *ptr)
ctimer_set(&instance->dao_retransmit_timer,
RPL_DAO_RETRANSMISSION_TIMEOUT / 2 +
(random_rand() % (RPL_DAO_RETRANSMISSION_TIMEOUT / 2)),
handle_dao_retransmission, parent);
handle_dao_retransmission, parent);
instance->my_dao_transmissions++;
dao_output_target_seq(parent, &prefix,
instance->default_lifetime, instance->my_dao_seqno);
instance->default_lifetime, instance->my_dao_seqno);
}
#endif /* RPL_WITH_DAO_ACK */
/*---------------------------------------------------------------------------*/
@ -1113,11 +1104,11 @@ dao_output(rpl_parent_t *parent, uint8_t lifetime)
instance->my_dao_seqno = dao_sequence;
instance->my_dao_transmissions = 1;
ctimer_set(&instance->dao_retransmit_timer, RPL_DAO_RETRANSMISSION_TIMEOUT,
handle_dao_retransmission, parent);
handle_dao_retransmission, parent);
}
#else
/* We know that we have tried to register so now we are assuming
that we have a down-link - unless this is a zero lifetime one */
/* We know that we have tried to register so now we are assuming
that we have a down-link - unless this is a zero lifetime one */
parent->dag->instance->has_downward_route = lifetime != RPL_ZERO_LIFETIME;
#endif /* RPL_WITH_DAO_ACK */
@ -1133,7 +1124,7 @@ dao_output_target(rpl_parent_t *parent, uip_ipaddr_t *prefix, uint8_t lifetime)
/*---------------------------------------------------------------------------*/
static void
dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
uint8_t lifetime, uint8_t seq_no)
uint8_t lifetime, uint8_t seq_no)
{
rpl_dag_t *dag;
rpl_instance_t *instance;
@ -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
@ -1233,7 +1224,7 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
}
PRINTF("RPL: Sending a %sDAO with sequence number %u, lifetime %u, prefix ",
lifetime == RPL_ZERO_LIFETIME ? "No-Path " : "", seq_no, lifetime);
lifetime == RPL_ZERO_LIFETIME ? "No-Path " : "", seq_no, lifetime);
PRINT6ADDR(prefix);
PRINTF(" to ");
@ -1283,8 +1274,8 @@ dao_ack_input(void)
}
PRINTF("RPL: Received a DAO %s with sequence number %d (%d) and status %d from ",
status < 128 ? "ACK" : "NACK",
sequence, instance->my_dao_seqno, status);
status < 128 ? "ACK" : "NACK",
sequence, instance->my_dao_seqno, status);
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n");
@ -1343,7 +1334,7 @@ dao_ack_input(void)
/*---------------------------------------------------------------------------*/
void
dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence,
uint8_t status)
uint8_t status)
{
#if RPL_WITH_DAO_ACK
unsigned char *buffer;

View file

@ -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 */

View file

@ -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();

View file

@ -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__ */
/** @} */
/** @} */

View file

@ -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 */

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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");
}
/*-----------------------------------------------------------------------------------*/

View file

@ -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,35 +77,29 @@ 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();
}
cfs_close(file);
log_message("IP Address: ", ipaddrtoa(&config.hostaddr, uip_buf));
log_message("Subnet Mask: ", ipaddrtoa(&config.netmask, uip_buf));
log_message("Def. Router: ", ipaddrtoa(&config.draddr, uip_buf));
log_message("DNS Server: ", ipaddrtoa(&config.resolvaddr, uip_buf));
log_message("IP Address: ", ipaddrtoa(&config.hostaddr, uip_buf));
log_message("Subnet Mask: ", ipaddrtoa(&config.netmask, uip_buf));
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;
}
/*-----------------------------------------------------------------------------------*/

View file

@ -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_ */

View file

@ -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);

View file

@ -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

View file

@ -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,42 +59,25 @@ 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":
": No module");
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);
}
/*---------------------------------------------------------------------------*/

View file

@ -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);

View file

@ -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 */

View file

@ -1,6 +0,0 @@
CONTIKI_PROJECT = serconfig
all: $(CONTIKI_PROJECT)
CONTIKI = ../../..
CONTIKI_WITH_IPV4 = 1
include $(CONTIKI)/Makefile.include

View file

@ -1 +0,0 @@
DEFINES = WITH_PFS

View file

@ -1 +0,0 @@
DEFINES = WITH_PFS

View file

@ -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, &params, sizeof(params));
cfs_close(f);
printf("Saving Config - Done\n");
}
/*-----------------------------------------------------------------------------------*/

View file

@ -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

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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

Some files were not shown because too many files have changed in this diff Show more