Compare commits

..

14 commits
master ... ico

Author SHA1 Message Date
Ralf Schlatterbeck 6c63efc84e Add noflashboot to config file
Don't load application from flash after timeout, makes it work for
long ssh connection times when the raspi has no DNS and produces DNS
timeouts too long for the bootloader. Note that this needs a new icosoc
(at the time of this commit).
2016-09-29 21:24:29 +02:00
Harald Pichler 0d797cf90a initial upload 2016-08-16 21:19:49 +02:00
Ralf Schlatterbeck fab42e0d67 Changes for new icoboard
We now have more memory, so no need to compile for flash.
2016-06-30 12:57:32 +02:00
Ralf Schlatterbeck 7d63a0f487 Merge branch 'osd' into ico
Conflicts resolved:
	core/net/mac/contikimac/contikimac.c
2016-06-30 09:28:54 +02:00
Ralf Schlatterbeck d78269ffc1 Working wallclock example
.. and cron probably would work if we had something to switch on/off for
testing.
2016-05-13 16:01:10 +02:00
Ralf Schlatterbeck b87ba1f526 Working ping
Biggest problem was definitions in rtimer_arch.h -- we have a 16-bit
rtimer_clock_t so this was overflowing and not working. Therefore most
delays in the radio implementation didn't work.
2016-05-12 14:00:53 +02:00
Ralf Schlatterbeck cb1e085ebf First implementation of cc2520 radio
Can write and read memory of radio chip. No communication with
merkur-board so far.
2016-05-08 21:20:58 +02:00
Ralf Schlatterbeck b9fc6a8324 Fix for hardware with less gpio pins
Some implementations don't have enough pins to implement CC2520_FIFO on a
separate pin. By not defining CC2520_FIFO_IS_1 an alternative
implementation uses an spi command to retrieve the FIFO overflow
exception info.
2016-05-08 16:44:49 +02:00
Ralf Schlatterbeck d7e6935ec2 Channel check interval is clock_time_t
Fix channel_check_interval routine in struct rdc_driver to be of type
clock_time_t -- otherwise this may overflow on some architectures.
2016-05-07 11:46:27 +02:00
Ralf Schlatterbeck 0232e6c9dc Implement etimer callback 2016-05-05 16:32:31 +02:00
Ralf Schlatterbeck c043a00bb4 Working CPU-Timer
As long as sleep time in wallclock-example is short enough, we're
scheduled by the etimer -- since etimer callback is missing (no timer
interrupt yet) this doesn't work when time gets longer.
2016-04-15 20:06:28 +02:00
Ralf Schlatterbeck 08fb461f43 Start implementing timer 2016-04-15 09:54:44 +02:00
Ralf Schlatterbeck c49d4a0b36 Stripped-down version with icosoc routines
Version now is below 128k but doesn't include most application-specific
interesting stuff.
The icosoc routines for I/O are now linked in (thanks to Clifford for
spotting this) and we have debug output.
Current code is enough to get cooperative multitasking and timers
working and tested, this is next todo.
2016-04-01 18:26:59 +02:00
Ralf Schlatterbeck 57959a53f6 Initial PicoRV32 target 2016-03-31 12:47:05 +02:00
1412 changed files with 17702 additions and 159382 deletions

14
.gitmodules vendored
View file

@ -4,15 +4,13 @@
[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/g-oikonomou/cc26xxware.git
[submodule "cpu/cc26xx-cc13xx/lib/cc13xxware"]
path = cpu/cc26xx-cc13xx/lib/cc13xxware
url = https://github.com/contiki-os/cc13xxware.git
path = cpu/cc26xx-c../.gitmodulesc13xx/lib/cc13xxware
url = https://github.com/g-oikonomou/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

@ -1,7 +1,3 @@
# Workaround for the issue found in the stable image promoted on Dec 1, 2016.
# See https://github.com/travis-ci/travis-ci/issues/6928#issuecomment-264227708
group: deprecated
notifications:
email: false
language: c #NOTE: this will set CC=gcc which might cause trouble
@ -14,7 +10,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 +81,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 &&
@ -162,5 +158,3 @@ env:
- BUILD_TYPE='slip-radio' MAKE_TARGETS='cooja'
- 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

@ -304,25 +304,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)

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

@ -49,77 +49,37 @@
*
*/
#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;
volatile uint8_t mcusleepcycleval;
/*-------------- 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;
mcusleepcycleval=mcusleepcycle;
}
void
mcu_sleep_on(void)
{
if(mcusleep == 0){
mcusleepcycle= mcusleepcycleval;
}
mcusleepcycle= mcusleepcycleval;
}
/*--------------- disable sleep mode ---------------------------------------*/
void
mcu_sleep_off(void)
{
mcusleepcycle=0;
mcusleepcycle=0;
}
/*---------------- set duty cycle value ------------------------------------*/
void
mcu_sleep_set(uint8_t value)
{
mcusleepcycleval= value;
// mcusleepcycle = mcusleepcycleval;
mcusleepcycle = mcusleepcycleval;
}
PROCESS(arduino_sketch, "Arduino Sketch Wrapper");
@ -127,54 +87,28 @@ 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);
if(etimer_expired(&loop_periodic_timer)) {
loop ();
etimer_reset(&loop_periodic_timer);
}
}
PROCESS_END();
}
/*
* VI settings, see coding style
* ex:ts=8:et:sw=2

View file

@ -52,12 +52,8 @@
#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---------------------------------------*/
/*--------------- disable sleep mode ---------------------------------------*/
void mcu_sleep_off(void);
/*---------------- set sleep value ------------------------------------*/
void mcu_sleep_set(uint8_t value);
@ -65,7 +61,6 @@ 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;

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

@ -119,20 +119,6 @@ static const char *get_uri (void *request)
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
@ -141,20 +127,14 @@ void generic_get_handler
, 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
)
, size_t (*to_str)(const char *name, const char *uri, 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);
const char *uri = get_uri (request);
REST.get_header_accept (request, &accept);
if ( accept != -1
@ -180,7 +160,7 @@ void generic_get_handler
success = 0;
goto out;
}
len += to_str (name, uri, query, temp + len, sizeof (temp) - len);
len += to_str (name, uri, temp + len, sizeof (temp) - len);
if (len > sizeof (temp)) {
success = 0;
goto out;
@ -196,7 +176,7 @@ void generic_get_handler
goto out;
}
} else { // TEXT Format
len += to_str (name, uri, query, temp + len, sizeof (temp) - len);
len += to_str (name, uri, temp + len, sizeof (temp) - len);
if (len > sizeof (temp)) {
success = 0;
goto out;
@ -223,8 +203,7 @@ void generic_put_handler
, 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 (*from_str)(const char *name, const char *uri, const char *s)
)
{
int success = 1;
@ -233,7 +212,6 @@ void generic_put_handler
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))) {
@ -248,7 +226,7 @@ void generic_put_handler
goto out;
}
}
if (from_str (name, uri, query, temp) < 0) {
if (from_str (name, uri, temp) < 0) {
success = 0;
} else {
REST.set_response_status (response, REST.status.CHANGED);

View file

@ -50,9 +50,8 @@
#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
#define MAX_GET_STRING_LENGTH 100
#define MAX_URI_STRING_LENGTH 30
/*
* A macro that extends the resource definition and also sets up the
@ -125,8 +124,11 @@ extern int8_t json_parse_variable
*
* 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.
* parameters.
* For the to_str function the is_json flag allows to generate a
* different string depending on the content-type. 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
@ -136,13 +138,7 @@ extern void generic_get_handler
, 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
)
, size_t (*to_str)(const char *name, const char *uri, char *buf, size_t bsize)
);
/**
@ -165,8 +161,7 @@ extern void generic_put_handler
, 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 (*from_str)(const char *name, const char *uri, const char *s)
);
/*

View file

@ -65,7 +65,7 @@
/*---------------------------------------------------------------------------*/
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINTF(...) PRINTF(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
@ -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

@ -587,40 +587,6 @@ get_resource(const lwm2m_instance_t *instance, lwm2m_context_t *context)
return NULL;
}
/*---------------------------------------------------------------------------*/
/**
* @brief Write a list of object instances as a CoRE Link-format list
*/
static int
write_object_instances_link(const lwm2m_object_t *object,
char *buffer, size_t size)
{
const lwm2m_instance_t *instance;
int len, rdlen, i;
PRINTF("</%d>", object->id);
rdlen = snprintf(buffer, size, "</%d>",
object->id);
if(rdlen < 0 || rdlen >= size) {
return -1;
}
for(i = 0; i < object->count; i++) {
if((object->instances[i].flag & LWM2M_INSTANCE_FLAG_USED) == 0) {
continue;
}
instance = &object->instances[i];
PRINTF(",</%d/%d>", object->id, instance->id);
len = snprintf(&buffer[rdlen], size - rdlen,
",<%d/%d>", object->id, instance->id);
rdlen += len;
if(len < 0 || rdlen >= size) {
return -1;
}
}
return rdlen;
}
/*---------------------------------------------------------------------------*/
static int
write_rd_link_data(const lwm2m_object_t *object,
const lwm2m_instance_t *instance,
@ -1086,23 +1052,6 @@ lwm2m_engine_handler(const lwm2m_object_t *object,
REST.set_header_content_type(response, LWM2M_JSON);
}
}
} else if(depth == 1) {
/* produce a list of instances */
if(method != METHOD_GET) {
REST.set_response_status(response, METHOD_NOT_ALLOWED_4_05);
} else {
int rdlen;
PRINTF("Sending instance list for object %u\n", object->id);
/* TODO: if(accept == APPLICATION_LINK_FORMAT) { */
rdlen = write_object_instances_link(object, (char *)buffer, preferred_size);
if(rdlen < 0) {
PRINTF("Failed to generate object response\n");
REST.set_response_status(response, SERVICE_UNAVAILABLE_5_03);
return;
}
REST.set_header_content_type(response, REST.type.APPLICATION_LINK_FORMAT);
REST.set_response_payload(response, buffer, rdlen);
}
}
}
/*---------------------------------------------------------------------------*/

View file

@ -45,14 +45,6 @@
#include "net/ipv6/uip-ds6-route.h"
#include "net/packetbuf.h"
#include "net/rpl/rpl-conf.h"
#include "net/rpl/rpl-private.h"
/*
* The body of this rule should be compiled only when "nbr_routes" is available,
* otherwise a link error causes build failure. "nbr_routes" is compiled if
* UIP_CONF_MAX_ROUTES != 0. See uip-ds6-route.c.
*/
#if UIP_CONF_MAX_ROUTES != 0
#if ORCHESTRA_UNICAST_SENDER_BASED && ORCHESTRA_COLLISION_FREE_HASH
#define UNICAST_SLOT_SHARED_FLAG ((ORCHESTRA_UNICAST_PERIOD < (ORCHESTRA_MAX_HASH + 1)) ? LINK_OPTION_SHARED : 0)
@ -219,5 +211,3 @@ struct orchestra_rule unicast_per_neighbor_rpl_storing = {
child_added,
child_removed,
};
#endif /* UIP_MAX_ROUTES */

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

@ -113,14 +113,6 @@ rest_activate_resource(resource_t *resource, char *path)
PRINTF("Periodic resource: %p (%s)\n", resource->periodic,
resource->periodic->resource->url);
list_add(restful_periodic_services, resource->periodic);
if(process_is_running(&rest_engine_process)) {
PRINTF("Periodic: Set timer for /%s to %lu\n",
resource->url, resource->periodic->period);
PROCESS_CONTEXT_BEGIN(&rest_engine_process);
etimer_set(&resource->periodic->periodic_timer,
resource->periodic->period);
PROCESS_CONTEXT_END(&rest_engine_process);
}
}
}
/*---------------------------------------------------------------------------*/

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

@ -35,8 +35,7 @@ static size_t get_index_from_uri (const char *uri)
return idx;
}
int crontab_from_string
(const char *name, const char *uri, const char *query, const char *s)
int crontab_from_string (const char *name, const char *uri, const char *s)
{
const char *err;
int res;
@ -53,13 +52,7 @@ int crontab_from_string
}
size_t
crontab_to_string
( const char *name
, const char *uri
, const char *query
, char *buf
, size_t bsize
)
crontab_to_string (const char *name, const char *uri, 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

View file

@ -17,8 +17,7 @@
#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)
size_t time_to_string (const char *name, const char *uri, char *buf, size_t bs)
{
struct xtimeval tv;
struct xtm tm;

View file

@ -21,8 +21,7 @@
#include "er-coap.h"
#include "generic_resource.h"
int timestamp_from_string
(const char *name, const char *uri, const char *query, const char *s)
int timestamp_from_string (const char *name, const char *uri, const char *s)
{
struct xtimeval tv;
// FIXME: Platform has no strtoll (long long)?
@ -32,13 +31,7 @@ int timestamp_from_string
}
size_t
timestamp_to_string
( const char *name
, const char *uri
, const char *query
, char *buf
, size_t bsize
)
timestamp_to_string (const char *name, const char *uri, char *buf, size_t bsize)
{
struct xtimeval tv;
xgettimeofday (&tv, NULL);

View file

@ -17,21 +17,14 @@
#include "er-coap.h"
#include "generic_resource.h"
int timezone_from_string
(const char *name, const char *uri, const char *query, const char *s)
int timezone_from_string (const char *name, const char *uri, 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
)
timezone_to_string (const char *name, const char *uri, char *buf, size_t bsize)
{
if (get_tz (buf, bsize) == NULL) {
*buf = '\0';

@ -1 +0,0 @@
Subproject commit e95b02584a0041817da67c8c01f2a197d0c26915

View file

@ -410,7 +410,6 @@ parse_tag(void)
switch_majorstate(s.lastmajorstate);
break;
case TAG_BODY:
do_word();
s.majorstate = s.lastmajorstate = MAJORSTATE_BODY;
break;
case TAG_IMG:

View file

@ -155,13 +155,10 @@ make_tcp_stats(void *arg)
{
struct uip_conn *conn;
struct httpd_state *s = (struct httpd_state *)arg;
#if NETSTACK_CONF_WITH_IPV6
char buf[48];
#endif
conn = &uip_conns[s->u.count];
#if NETSTACK_CONF_WITH_IPV6
char buf[48];
httpd_sprint_ip6(conn->ripaddr, buf);
return snprintf((char *)uip_appdata, uip_mss(),
"<tr align=\"center\"><td>%d</td><td>%s:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n",
@ -252,9 +249,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 +277,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 +309,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 +320,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

@ -1309,6 +1309,7 @@ cfs_coffee_configure_log(const char *filename, unsigned log_size,
return 0;
}
/*---------------------------------------------------------------------------*/
#if COFFEE_IO_SEMANTICS
int
cfs_coffee_set_io_semantics(int fd, unsigned flags)
{
@ -1320,6 +1321,7 @@ cfs_coffee_set_io_semantics(int fd, unsigned flags)
return 0;
}
#endif
/*---------------------------------------------------------------------------*/
int
cfs_coffee_format(void)

View file

@ -36,7 +36,6 @@
#include <dirent.h>
#include <string.h>
#define CFS_IMPL 1
#include "cfs/cfs.h"
struct cfs_posix_dir {

View file

@ -40,7 +40,6 @@
#include <unistd.h>
#endif
#define CFS_IMPL 1
#include "cfs/cfs.h"
/*---------------------------------------------------------------------------*/

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
@ -204,7 +211,7 @@
#define UIP_CONF_ND6_SEND_RA (NETSTACK_CONF_WITH_IPV6 && !UIP_CONF_IPV6_RPL)
#endif /* UIP_CONF_ND6_SEND_RA */
/* UIP_CONF_ND6_SEND_NS enables standard IPv6 Neighbor Discovery Protocol.
/* UIP_CONF_ND6_SEND_NA enables standard IPv6 Neighbor Discovery Protocol.
We enable it by default when IPv6 is used without RPL.
With RPL, the neighbor cache (link-local IPv6 <-> MAC address mapping)
is fed whenever receiving DIO and DAO messages. This is always sufficient
@ -214,15 +221,9 @@
neighbor to us is weak, if DIO transmissions are suppressed (Trickle
timer) or if the neighbor chooses not to transmit DIOs because it is
a leaf node or for any reason. */
#ifndef UIP_CONF_ND6_SEND_NS
#define UIP_CONF_ND6_SEND_NS (NETSTACK_CONF_WITH_IPV6 && !UIP_CONF_IPV6_RPL)
#endif /* UIP_CONF_ND6_SEND_NS */
/* UIP_CONF_ND6_SEND_NA allows to still comply with NDP even if the host does
not perform NUD or DAD processes. By default it is activated so the host
can still communicate with a full NDP peer. */
#ifndef UIP_CONF_ND6_SEND_NA
#define UIP_CONF_ND6_SEND_NA (NETSTACK_CONF_WITH_IPV6)
#endif /* UIP_CONF_ND6_SEND_NS */
#define UIP_CONF_ND6_SEND_NA (NETSTACK_CONF_WITH_IPV6 && !UIP_CONF_IPV6_RPL)
#endif /* UIP_CONF_ND6_SEND_NA */
/*---------------------------------------------------------------------------*/
/* 6lowpan configuration options.

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

@ -81,7 +81,7 @@ enum {
*/
static uint8_t state = STATE_TWOPACKETS;
static uint16_t begin, next_free;
static uint16_t begin, end;
static uint8_t rxbuf[RX_BUFSIZE];
static uint16_t pkt_end; /* SLIP_END tracker. */
@ -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);
@ -150,7 +153,7 @@ slip_write(const void *_ptr, int len)
static void
rxbuf_init(void)
{
begin = next_free = pkt_end = 0;
begin = end = pkt_end = 0;
state = STATE_OK;
}
/*---------------------------------------------------------------------------*/
@ -158,11 +161,10 @@ 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;
if(begin < next_free && (next_free - begin) >= 6
if(begin < end && (end - begin) >= 6
&& memcmp(&rxbuf[begin], "CLIENT", 6) == 0) {
state = STATE_TWOPACKETS; /* Interrupts do nothing. */
memset(&rxbuf[begin], 0x0, 6);
@ -175,14 +177,12 @@ 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 */
int i, j;
char* hexchar = "0123456789abcdef";
if(begin < next_free && (next_free - begin) >= 2
if(begin < end && (end - begin) >= 2
&& rxbuf[begin + 1] == 'M') {
state = STATE_TWOPACKETS; /* Interrupts do nothing. */
rxbuf[begin] = 0;
@ -210,109 +210,37 @@ slip_poll_handler(uint8_t *outbuf, uint16_t blen)
*/
if(begin != pkt_end) {
uint16_t len;
uint16_t cur_next_free;
uint16_t cur_ptr;
int esc = 0;
if(begin < pkt_end) {
uint16_t i;
len = 0;
for(i = begin; i < pkt_end; ++i) {
if(len > blen) {
len = 0;
break;
}
if (esc) {
if(rxbuf[i] == SLIP_ESC_ESC) {
outbuf[len] = SLIP_ESC;
len++;
} else if(rxbuf[i] == SLIP_ESC_END) {
outbuf[len] = SLIP_END;
len++;
}
esc = 0;
} else if(rxbuf[i] == SLIP_ESC) {
esc = 1;
} else {
outbuf[len] = rxbuf[i];
len++;
}
len = pkt_end - begin;
if(len > blen) {
len = 0;
} else {
memcpy(outbuf, &rxbuf[begin], len);
}
} else {
uint16_t i;
len = 0;
for(i = begin; i < RX_BUFSIZE; ++i) {
if(len > blen) {
len = 0;
break;
}
if (esc) {
if(rxbuf[i] == SLIP_ESC_ESC) {
outbuf[len] = SLIP_ESC;
len++;
} else if(rxbuf[i] == SLIP_ESC_END) {
outbuf[len] = SLIP_END;
len++;
}
esc = 0;
} else if(rxbuf[i] == SLIP_ESC) {
esc = 1;
} else {
outbuf[len] = rxbuf[i];
len++;
}
}
for(i = 0; i < pkt_end; ++i) {
if(len > blen) {
len = 0;
break;
}
if (esc) {
if(rxbuf[i] == SLIP_ESC_ESC) {
outbuf[len] = SLIP_ESC;
len++;
} else if(rxbuf[i] == SLIP_ESC_END) {
outbuf[len] = SLIP_END;
len++;
}
esc = 0;
} else if(rxbuf[i] == SLIP_ESC) {
esc = 1;
} else {
outbuf[len] = rxbuf[i];
len++;
}
len = (RX_BUFSIZE - begin) + (pkt_end - 0);
if(len > blen) {
len = 0;
} else {
unsigned i;
for(i = begin; i < RX_BUFSIZE; i++) {
*outbuf++ = rxbuf[i];
}
for(i = 0; i < pkt_end; i++) {
*outbuf++ = rxbuf[i];
}
}
}
/* Remove data from buffer together with the copied packet. */
pkt_end = pkt_end + 1;
if(pkt_end == RX_BUFSIZE) {
pkt_end = 0;
}
if(pkt_end != next_free) {
cur_next_free = next_free;
cur_ptr = pkt_end;
while(cur_ptr != cur_next_free) {
if(rxbuf[cur_ptr] == SLIP_END) {
uint16_t tmp_begin = pkt_end;
pkt_end = cur_ptr;
begin = tmp_begin;
/* One more packet is buffered, need to be polled again! */
process_poll(&slip_process);
break;
}
cur_ptr++;
if(cur_ptr == RX_BUFSIZE) {
cur_ptr = 0;
}
}
if(cur_ptr == cur_next_free) {
/* no more pending full packet found */
begin = pkt_end;
}
} else {
begin = pkt_end;
begin = pkt_end;
if(state == STATE_TWOPACKETS) {
pkt_end = end;
state = STATE_OK; /* Assume no bytes where lost! */
/* One more packet is buffered, need to be polled again! */
process_poll(&slip_process);
}
return len;
}
@ -388,71 +316,77 @@ PROCESS_THREAD(slip_process, ev, data)
int
slip_input_byte(unsigned char c)
{
uint16_t cur_end;
switch(state) {
case STATE_RUBBISH:
if(c == SLIP_END) {
state = STATE_OK;
}
return 0;
case STATE_TWOPACKETS: /* Two packets are already buffered! */
return 0;
case STATE_ESC:
if(c != SLIP_ESC_END && c != SLIP_ESC_ESC) {
if(c == SLIP_ESC_END) {
c = SLIP_END;
} else if(c == SLIP_ESC_ESC) {
c = SLIP_ESC;
} else {
state = STATE_RUBBISH;
SLIP_STATISTICS(slip_rubbish++);
next_free = pkt_end; /* remove rubbish */
end = pkt_end; /* remove rubbish */
return 0;
}
state = STATE_OK;
break;
}
if(c == SLIP_ESC) {
state = STATE_ESC;
case STATE_OK:
if(c == SLIP_ESC) {
state = STATE_ESC;
return 0;
} else if(c == SLIP_END) {
/*
* We have a new packet, possibly of zero length.
*
* There may already be one packet buffered.
*/
if(end != pkt_end) { /* Non zero length. */
if(begin == pkt_end) { /* None buffered. */
pkt_end = end;
} else {
state = STATE_TWOPACKETS;
SLIP_STATISTICS(slip_twopackets++);
}
process_poll(&slip_process);
return 1;
}
return 0;
}
break;
}
/* add_char: */
cur_end = next_free;
next_free = next_free + 1;
if(next_free == RX_BUFSIZE) {
next_free = 0;
{
unsigned next;
next = end + 1;
if(next == RX_BUFSIZE) {
next = 0;
}
if(next == begin) { /* rxbuf is full */
state = STATE_RUBBISH;
SLIP_STATISTICS(slip_overflow++);
end = pkt_end; /* remove rubbish */
return 0;
}
rxbuf[end] = c;
end = next;
}
if(next_free == begin) { /* rxbuf is full */
state = STATE_RUBBISH;
SLIP_STATISTICS(slip_overflow++);
next_free = pkt_end; /* remove rubbish */
return 0;
}
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) {
/*
* We have a new packet, possibly of zero length.
*
* There may already be one packet buffered.
*/
if(cur_end != pkt_end) { /* Non zero length. */
if(begin == pkt_end) { /* None buffered. */
pkt_end = cur_end;
} else {
SLIP_STATISTICS(slip_twopackets++);
}
process_poll(&slip_process);
return 1;
} else {
/* Empty packet, reset the pointer */
next_free = cur_end;
}
return 0;
}
return 0;
}

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

@ -29,9 +29,6 @@
*
*/
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
#include "contiki.h"
#include "sys/cc.h"
#include "contiki-net.h"
@ -40,8 +37,10 @@
#include "tcp-socket.h"
#include <stdio.h>
#include <string.h>
static void relisten(struct tcp_socket *s);
LIST(socketlist);
@ -81,7 +80,7 @@ acked(struct tcp_socket *s)
s->output_data_maxlen - s->output_data_send_nxt);
}
if(s->output_data_len < s->output_data_send_nxt) {
PRINTF("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
s->output_data_len,
s->output_data_send_nxt);
tcp_markconn(uip_conn, NULL);
@ -122,7 +121,7 @@ newdata(struct tcp_socket *s)
bytesleft = 0;
}
if(bytesleft > 0) {
PRINTF("tcp: newdata, bytesleft > 0 (%d) not implemented\n", bytesleft);
printf("tcp: newdata, bytesleft > 0 (%d) not implemented\n", bytesleft);
}
dataptr += copylen;
len -= copylen;
@ -357,8 +356,6 @@ tcp_socket_send(struct tcp_socket *s,
s->output_senddata_len = s->output_data_len;
}
tcpip_poll_tcp(s->c);
return len;
}
/*---------------------------------------------------------------------------*/
@ -401,9 +398,3 @@ tcp_socket_max_sendlen(struct tcp_socket *s)
return s->output_data_maxlen - s->output_data_len;
}
/*---------------------------------------------------------------------------*/
int
tcp_socket_queuelen(struct tcp_socket *s)
{
return s->output_data_len;
}
/*---------------------------------------------------------------------------*/

View file

@ -284,16 +284,4 @@ int tcp_socket_unregister(struct tcp_socket *s);
*/
int tcp_socket_max_sendlen(struct tcp_socket *s);
/**
* \brief The number of bytes waiting to be sent
* \param s A pointer to a TCP socket
* \return The number of bytes that have not yet been acknowledged by the receiver.
*
* This function queries the TCP socket and returns the
* number of bytes that are currently not yet known to
* have been successfully received by the receiver.
*
*/
int tcp_socket_queuelen(struct tcp_socket *s);
#endif /* TCP_SOCKET_H */

View file

@ -548,15 +548,6 @@ tcpip_ipv6_output(void)
return;
}
#if UIP_CONF_IPV6_RPL
if(!rpl_update_header()) {
/* Packet can not be forwarded */
PRINTF("tcpip_ipv6_output: RPL header update error\n");
uip_clear_buf();
return;
}
#endif /* UIP_CONF_IPV6_RPL */
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
/* Next hop determination */
@ -660,9 +651,15 @@ tcpip_ipv6_output(void)
/* End of next hop determination */
#if UIP_CONF_IPV6_RPL
if(!rpl_finalize_header(nexthop)) {
uip_clear_buf();
return;
}
#endif /* UIP_CONF_IPV6_RPL */
nbr = uip_ds6_nbr_lookup(nexthop);
if(nbr == NULL) {
#if UIP_ND6_SEND_NS
#if UIP_ND6_SEND_NA
if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE, NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
uip_clear_buf();
PRINTF("tcpip_ipv6_output: failed to add neighbor to cache\n");
@ -691,13 +688,13 @@ tcpip_ipv6_output(void)
nbr->nscount = 1;
/* Send the first NS try from here (multicast destination IP address). */
}
#else /* UIP_ND6_SEND_NS */
#else /* UIP_ND6_SEND_NA */
PRINTF("tcpip_ipv6_output: neighbor not in cache\n");
uip_len = 0;
return;
#endif /* UIP_ND6_SEND_NS */
#endif /* UIP_ND6_SEND_NA */
} else {
#if UIP_ND6_SEND_NS
#if UIP_ND6_SEND_NA
if(nbr->state == NBR_INCOMPLETE) {
PRINTF("tcpip_ipv6_output: nbr cache entry incomplete\n");
#if UIP_CONF_IPV6_QUEUE_PKT
@ -719,7 +716,7 @@ tcpip_ipv6_output(void)
nbr->nscount = 0;
PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n");
}
#endif /* UIP_ND6_SEND_NS */
#endif /* UIP_ND6_SEND_NA */
tcpip_output(uip_ds6_nbr_get_ll(nbr));

4
core/net/ip/uip-debug.c Executable file → Normal file
View file

@ -56,7 +56,7 @@ uip_debug_ipaddr_print(const uip_ipaddr_t *addr)
#if NETSTACK_CONF_WITH_IPV6
if(ip64_addr_is_ipv4_mapped_addr(addr)) {
/*
* Printing IPv4-mapped addresses is done according to RFC 4291 [1]
* Printing IPv4-mapped addresses is done according to RFC 3513 [1]
*
* "An alternative form that is sometimes more
* convenient when dealing with a mixed environment
@ -67,7 +67,7 @@ uip_debug_ipaddr_print(const uip_ipaddr_t *addr)
* low-order 8-bit pieces of the address (standard
* IPv4 representation)."
*
* [1] https://tools.ietf.org/html/rfc4291#page-4
* [1] https://tools.ietf.org/html/rfc3513#page-5
*/
PRINTA("::FFFF:%u.%u.%u.%u", addr->u8[12], addr->u8[13], addr->u8[14], addr->u8[15]);
} else {

28
core/net/ip/uip.h Executable file → Normal file
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 {
@ -1994,7 +2012,7 @@ CCIF extern uip_lladdr_t uip_lladdr;
(((a)->u8[15]) == 0x02))
/**
* \brief is addr (a) a link local unicast address, see RFC 4291
* \brief is addr (a) a link local unicast address, see RFC3513
* i.e. is (a) on prefix FE80::/10
* a is of type uip_ipaddr_t*
*/
@ -2018,7 +2036,7 @@ CCIF extern uip_lladdr_t uip_lladdr;
} while(0)
/**
* \brief is addr (a) a solicited node multicast address, see RFC 4291
* \brief is addr (a) a solicited node multicast address, see RFC3513
* a is of type uip_ipaddr_t*
*/
#define uip_is_addr_solicited_node(a) \
@ -2079,7 +2097,7 @@ CCIF extern uip_lladdr_t uip_lladdr;
#endif /*UIP_CONF_LL_802154*/
/**
* \brief is address a multicast address, see RFC 4291
* \brief is address a multicast address, see RFC 3513
* a is of type uip_ipaddr_t*
* */
#define uip_is_addr_mcast(a) \

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

@ -7,14 +7,8 @@ What does it do
These files, alongside some core modifications, add support for IPv6 multicast
to contiki's uIPv6 engine.
Currently, three modes are supported:
Currently, two modes are supported:
* 'Enhanced Stateless Multicast RPL Forwarding' (ESMRF)
ESMRF is an enhanced version of the SMRF engine with the aim
of resolving the sending limitation of SMRF to allow any node
within the DODAG to send multicast traffic up and down the RPL tree.
ESMRF is documented here:
http://dl.acm.org/citation.cfm?id=2753479
* 'Stateless Multicast RPL Forwarding' (SMRF)
RPL in MOP 3 handles group management as per the RPL docs,
SMRF is a lightweight engine which handles datagram forwarding.

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

@ -88,23 +88,19 @@ uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
, reason, data);
if(nbr) {
uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
#if UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
nbr->isrouter = isrouter;
#endif /* UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
nbr->state = state;
#if UIP_CONF_IPV6_QUEUE_PKT
uip_packetqueue_new(&nbr->packethandle);
#endif /* UIP_CONF_IPV6_QUEUE_PKT */
#if UIP_ND6_SEND_NS
if(nbr->state == NBR_REACHABLE) {
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
} else {
/* We set the timer in expired state */
stimer_set(&nbr->reachable, 0);
}
#if UIP_ND6_SEND_NA
/* timers are set separately, for now we put them in expired state */
stimer_set(&nbr->reachable, 0);
stimer_set(&nbr->sendns, 0);
nbr->nscount = 0;
#endif /* UIP_ND6_SEND_NS */
#endif /* UIP_ND6_SEND_NA */
PRINTF("Adding neighbor with ip addr ");
PRINT6ADDR(ipaddr);
PRINTF(" link addr ");
@ -245,7 +241,7 @@ uip_ds6_link_neighbor_callback(int status, int numtx)
#endif /* UIP_DS6_LL_NUD */
}
#if UIP_ND6_SEND_NS
#if UIP_ND6_SEND_NA
/*---------------------------------------------------------------------------*/
/** Periodic processing on neighbors */
void
@ -326,18 +322,6 @@ uip_ds6_neighbor_periodic(void)
}
}
/*---------------------------------------------------------------------------*/
void
uip_ds6_nbr_refresh_reachable_state(const uip_ipaddr_t *ipaddr)
{
uip_ds6_nbr_t *nbr;
nbr = uip_ds6_nbr_lookup(ipaddr);
if(nbr != NULL) {
nbr->state = NBR_REACHABLE;
nbr->nscount = 0;
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
}
}
/*---------------------------------------------------------------------------*/
uip_ds6_nbr_t *
uip_ds6_get_least_lifetime_neighbor(void)
{
@ -356,6 +340,6 @@ uip_ds6_get_least_lifetime_neighbor(void)
}
return nbr_expiring;
}
#endif /* UIP_ND6_SEND_NS */
#endif /* UIP_ND6_SEND_NA */
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -50,6 +50,8 @@
#include "net/nbr-table.h"
#include "sys/stimer.h"
#include "net/ipv6/uip-ds6.h"
#include "net/nbr-table.h"
#if UIP_CONF_IPV6_QUEUE_PKT
#include "net/ip/uip-packetqueue.h"
#endif /*UIP_CONF_QUEUE_PKT */
@ -69,11 +71,11 @@ typedef struct uip_ds6_nbr {
uip_ipaddr_t ipaddr;
uint8_t isrouter;
uint8_t state;
#if UIP_ND6_SEND_NS || UIP_ND6_SEND_RA
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA
struct stimer reachable;
struct stimer sendns;
uint8_t nscount;
#endif /* UIP_ND6_SEND_NS || UIP_ND6_SEND_RA */
#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA */
#if UIP_CONF_IPV6_QUEUE_PKT
struct uip_packetqueue_handle packethandle;
#define UIP_DS6_NBR_PACKET_LIFETIME CLOCK_SECOND * 4
@ -98,17 +100,6 @@ void uip_ds6_link_neighbor_callback(int status, int numtx);
void uip_ds6_neighbor_periodic(void);
int uip_ds6_nbr_num(void);
#if UIP_ND6_SEND_NS
/**
* \brief Refresh the reachable state of a neighbor. This function
* may be called when a node receives an IPv6 message that confirms the
* reachability of a neighbor.
* \param ipaddr pointer to the IPv6 address whose neighbor reachability state
* should be refreshed.
*/
void uip_ds6_nbr_refresh_reachable_state(const uip_ipaddr_t *ipaddr);
#endif /* UIP_ND6_SEND_NS */
/**
* \brief
* This searches inside the neighbor table for the neighbor that is about to

View file

@ -573,12 +573,6 @@ uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
}
/*---------------------------------------------------------------------------*/
uip_ds6_defrt_t *
uip_ds6_defrt_head(void)
{
return list_head(defaultrouterlist);
}
/*---------------------------------------------------------------------------*/
uip_ds6_defrt_t *
uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, unsigned long interval)
{
uip_ds6_defrt_t *d;

View file

@ -82,10 +82,14 @@ void uip_ds6_notification_rm(struct uip_ds6_notification *n);
#endif
/* Routing table */
#ifdef UIP_CONF_MAX_ROUTES
#define UIP_DS6_ROUTE_NB UIP_CONF_MAX_ROUTES
#else /* UIP_CONF_MAX_ROUTES */
#ifndef UIP_CONF_MAX_ROUTES
#ifdef UIP_CONF_DS6_ROUTE_NBU
#define UIP_DS6_ROUTE_NB UIP_CONF_DS6_ROUTE_NBU
#else /* UIP_CONF_DS6_ROUTE_NBU */
#define UIP_DS6_ROUTE_NB 4
#endif /* UIP_CONF_DS6_ROUTE_NBU */
#else /* UIP_CONF_MAX_ROUTES */
#define UIP_DS6_ROUTE_NB UIP_CONF_MAX_ROUTES
#endif /* UIP_CONF_MAX_ROUTES */
/** \brief define some additional RPL related route state and
@ -177,7 +181,6 @@ typedef struct uip_ds6_defrt {
/** \name Default router list basic routines */
/** @{ */
uip_ds6_defrt_t *uip_ds6_defrt_head(void);
uip_ds6_defrt_t *uip_ds6_defrt_add(uip_ipaddr_t *ipaddr,
unsigned long interval);
void uip_ds6_defrt_rm(uip_ds6_defrt_t *defrt);

View file

@ -187,9 +187,9 @@ uip_ds6_periodic(void)
}
#endif /* !UIP_CONF_ROUTER */
#if UIP_ND6_SEND_NS
#if UIP_ND6_SEND_NA
uip_ds6_neighbor_periodic();
#endif /* UIP_ND6_SEND_NS */
#endif /* UIP_ND6_SEND_RA */
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
/* Periodic RA sending */

View file

@ -56,8 +56,6 @@
* - the number of elements requested by the user in contiki configuration (name suffixed by _NBU)
* - the number of elements assigned by the system (name suffixed by _NBS)
* - the total number of elements is the sum (name suffixed by _NB)
* The routing table definitions can be found in uip-ds6-route.h
* The Neighbor cache definitions can be found in nbr-table.h
*/
/* Default router list */

View file

@ -160,6 +160,11 @@ echo_request_input(void)
uip_ext_len = 0;
}
/* Insert RPL extension headers */
#if UIP_CONF_IPV6_RPL
rpl_insert_header();
#endif /* UIP_CONF_IPV6_RPL */
/* Below is important for the correctness of UIP_ICMP_BUF and the
* checksum
*/
@ -255,6 +260,10 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) {
UIP_ICMP_BUF->icmpchksum = 0;
UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
#if UIP_CONF_IPV6_RPL
rpl_insert_header();
#endif /* UIP_CONF_IPV6_RPL */
UIP_STAT(++uip_stat.icmp.sent);
PRINTF("Sending ICMPv6 ERROR message type %d code %d to ", type, code);
@ -292,6 +301,9 @@ uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
UIP_STAT(++uip_stat.icmp.sent);
UIP_STAT(++uip_stat.ip.sent);
#if UIP_CONF_IPV6_RPL
rpl_insert_header();
#endif /* UIP_CONF_IPV6_RPL */
tcpip_ipv6_output();
}
/*---------------------------------------------------------------------------*/

View file

@ -116,16 +116,13 @@ void uip_log(char *msg);
#define UIP_ND6_OPT_RDNSS_BUF ((uip_nd6_opt_dns *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
/** @} */
#if UIP_ND6_SEND_NS || UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
static uint8_t nd6_opt_offset; /** Offset from the end of the icmpv6 header to the option in uip_buf*/
static uint8_t *nd6_opt_llao; /** Pointer to llao option in uip_buf */
static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/
static uip_ds6_addr_t *addr; /** Pointer to an interface address */
#endif /* UIP_ND6_SEND_NS || UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
#if UIP_ND6_SEND_NS || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */
#endif /* UIP_ND6_SEND_NS || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
static uip_ds6_addr_t *addr; /** Pointer to an interface address */
#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
#if !UIP_CONF_ROUTER // TBD see if we move it to ra_input
static uip_nd6_opt_prefix_info *nd6_opt_prefix_info; /** Pointer to prefix information option in uip_buf */
@ -160,27 +157,7 @@ create_llao(uint8_t *llao, uint8_t type) {
}
/*------------------------------------------------------------------*/
/**
* Neighbor Solicitation Processing
*
* The NS can be received in 3 cases (procedures):
* - sender is performing DAD (ip src = unspecified, no SLLAO option)
* - sender is performing NUD (ip dst = unicast)
* - sender is performing address resolution (ip dest = solicited node mcast
* address)
*
* We do:
* - if the tgt belongs to me, reply, otherwise ignore
* - if i was performing DAD for the same address, two cases:
* -- I already sent a NS, hence I win
* -- I did not send a NS yet, hence I lose
*
* If we need to send a NA in response (i.e. the NS was done for NUD, or
* address resolution, or DAD and there is a conflict), we do it in this
* function: set src, dst, tgt address in the three cases, then for all cases
* set the rest, including SLLAO
*
*/
#if UIP_ND6_SEND_NA
static void
ns_input(void)
@ -261,9 +238,9 @@ ns_input(void)
addr = uip_ds6_addr_lookup(&UIP_ND6_NS_BUF->tgtipaddr);
if(addr != NULL) {
#if UIP_ND6_DEF_MAXDADNS > 0
if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
/* DAD CASE */
#if UIP_ND6_DEF_MAXDADNS > 0
#if UIP_CONF_IPV6_CHECKS
if(!uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) {
PRINTF("NS received is bad\n");
@ -281,7 +258,9 @@ ns_input(void)
goto discard;
}
#else /* UIP_ND6_DEF_MAXDADNS > 0 */
goto discard; /* DAD CASE */
if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
/* DAD CASE */
goto discard;
#endif /* UIP_ND6_DEF_MAXDADNS > 0 */
}
#if UIP_CONF_IPV6_CHECKS
@ -369,7 +348,6 @@ discard:
/*------------------------------------------------------------------*/
#if UIP_ND6_SEND_NS
void
uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
{
@ -432,9 +410,7 @@ uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
PRINTF("\n");
return;
}
#endif /* UIP_ND6_SEND_NS */
#if UIP_ND6_SEND_NS
#if UIP_ND6_SEND_NA
/*------------------------------------------------------------------*/
/**
* Neighbor Advertisement Processing
@ -546,11 +522,14 @@ na_input(void)
goto discard;
}
/* Note: No need to refresh the state of the nbr here.
* It has already been refreshed upon receiving the unicast IPv6 ND packet.
* See: uip_ds6_nbr_refresh_reachable_state()
*/
if(!is_solicited) {
if(is_solicited) {
nbr->state = NBR_REACHABLE;
nbr->nscount = 0;
/* reachable time is stored in ms */
stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000);
} else {
nbr->state = NBR_STALE;
}
nbr->isrouter = is_router;
@ -573,10 +552,11 @@ na_input(void)
goto discard;
}
}
/* Note: No need to refresh the state of the nbr here.
* It has already been refreshed upon receiving the unicast IPv6 ND packet.
* See: uip_ds6_nbr_refresh_reachable_state()
*/
if(is_solicited) {
nbr->state = NBR_REACHABLE;
/* reachable time is stored in ms */
stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000);
}
}
}
if(nbr->isrouter && !is_router) {
@ -609,7 +589,7 @@ discard:
uip_clear_buf();
return;
}
#endif /* UIP_ND6_SEND_NS */
#endif /* UIP_ND6_SEND_NA */
#if UIP_CONF_ROUTER
#if UIP_ND6_SEND_RA
@ -682,8 +662,7 @@ rs_input(void)
}
if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
lladdr, UIP_LLADDR_LEN) != 0) {
uip_ds6_nbr_t nbr_data;
nbr_data = *nbr;
uip_ds6_nbr_t nbr_data = *nbr;
uip_ds6_nbr_rm(nbr);
nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned,
0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL);
@ -1103,8 +1082,6 @@ discard:
#if UIP_ND6_SEND_NA
UIP_ICMP6_HANDLER(ns_input_handler, ICMP6_NS, UIP_ICMP6_HANDLER_CODE_ANY,
ns_input);
#endif
#if UIP_ND6_SEND_NS
UIP_ICMP6_HANDLER(na_input_handler, ICMP6_NA, UIP_ICMP6_HANDLER_CODE_ANY,
na_input);
#endif
@ -1122,17 +1099,20 @@ UIP_ICMP6_HANDLER(ra_input_handler, ICMP6_RA, UIP_ICMP6_HANDLER_CODE_ANY,
void
uip_nd6_init()
{
#if UIP_ND6_SEND_NA
/* Only handle NSs if we are prepared to send out NAs */
uip_icmp6_register_input_handler(&ns_input_handler);
#endif
#if UIP_ND6_SEND_NS
/*
* Only handle NAs if we are prepared to send out NSs. */
* Only handle NAs if we are prepared to send out NAs.
* This is perhaps logically incorrect, but this condition was present in
* uip_process and we keep it until proven wrong
*/
uip_icmp6_register_input_handler(&na_input_handler);
#endif
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
/* Only accept RS if we are a router and happy to send out RAs */
uip_icmp6_register_input_handler(&rs_input_handler);

View file

@ -60,23 +60,11 @@
/** \name RFC 4861 Host constant */
/** @{ */
/** \brief Maximum router solicitation delay */
#ifndef UIP_CONF_ND6_MAX_RTR_SOLICITATION_DELAY
#define UIP_ND6_MAX_RTR_SOLICITATION_DELAY 1
#else
#define UIP_ND6_MAX_RTR_SOLICITATION_DELAY UIP_CONF_ND6_MAX_RTR_SOLICITATION_DELAY
#endif
/** \brief Router solicitation interval */
#ifndef UIP_CONF_ND6_RTR_SOLICITATION_INTERVAL
#define UIP_ND6_RTR_SOLICITATION_INTERVAL 4
#else
#define UIP_ND6_RTR_SOLICITATION_INTERVAL UIP_CONF_ND6_RTR_SOLICITATION_INTERVAL
#endif
/** \brief Maximum router solicitations */
#ifndef UIP_CONF_ND6_MAX_RTR_SOLICITATIONS
#define UIP_ND6_MAX_RTR_SOLICITATIONS 3
#else
#define UIP_ND6_MAX_RTR_SOLICITATIONS UIP_CONF_ND6_MAX_RTR_SOLICITATIONS
#endif
/** @} */
/** \name RFC 4861 Router constants */
@ -86,11 +74,6 @@
#else
#define UIP_ND6_SEND_RA UIP_CONF_ND6_SEND_RA
#endif
#ifndef UIP_CONF_ND6_SEND_NS
#define UIP_ND6_SEND_NS 1 /* enable/disable NS sending */
#else
#define UIP_ND6_SEND_NS UIP_CONF_ND6_SEND_NS
#endif
#ifndef UIP_CONF_ND6_SEND_NA
#define UIP_ND6_SEND_NA 1 /* enable/disable NA sending */
#else
@ -108,11 +91,7 @@
#endif
#define UIP_ND6_M_FLAG 0
#define UIP_ND6_O_FLAG (UIP_ND6_RA_RDNSS || UIP_ND6_RA_DNSSL)
#ifndef UIP_CONF_ROUTER_LIFETIME
#define UIP_ND6_ROUTER_LIFETIME 3 * UIP_ND6_MAX_RA_INTERVAL
#else
#define UIP_ND6_ROUTER_LIFETIME UIP_CONF_ROUTER_LIFETIME
#endif
#define UIP_ND6_MAX_INITIAL_RA_INTERVAL 16 /*seconds*/
#define UIP_ND6_MAX_INITIAL_RAS 3 /*transmissions*/
@ -130,7 +109,7 @@
#if UIP_CONF_LL_802154
#define UIP_ND6_DEF_MAXDADNS 0
#else /* UIP_CONF_LL_802154 */
#define UIP_ND6_DEF_MAXDADNS UIP_ND6_SEND_NS
#define UIP_ND6_DEF_MAXDADNS UIP_ND6_SEND_NA
#endif /* UIP_CONF_LL_802154 */
#else /* UIP_CONF_ND6_DEF_MAXDADNS */
#define UIP_ND6_DEF_MAXDADNS UIP_CONF_ND6_DEF_MAXDADNS
@ -357,6 +336,30 @@ typedef struct uip_nd6_opt_redirected_hdr {
* @{
*/
/**
* \brief Process a neighbor solicitation
*
* The NS can be received in 3 cases (procedures):
* - sender is performing DAD (ip src = unspecified, no SLLAO option)
* - sender is performing NUD (ip dst = unicast)
* - sender is performing address resolution (ip dest = solicited node mcast
* address)
*
* We do:
* - if the tgt belongs to me, reply, otherwise ignore
* - if i was performing DAD for the same address, two cases:
* -- I already sent a NS, hence I win
* -- I did not send a NS yet, hence I lose
*
* If we need to send a NA in response (i.e. the NS was done for NUD, or
* address resolution, or DAD and there is a conflict), we do it in this
* function: set src, dst, tgt address in the three cases, then for all cases
* set the rest, including SLLAO
*
*/
void
uip_nd6_ns_input(void);
/**
* \brief Send a neighbor solicitation, send a Neighbor Advertisement
* \param src pointer to the src of the NS if known
* \param dest pointer to ip address to send the NS, for DAD or ADDR Resol,

View file

@ -73,7 +73,6 @@
#include "sys/cc.h"
#include "net/ip/uip.h"
#include "net/ip/uip_arch.h"
#include "net/ip/uipopt.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/ipv6/uip-nd6.h"
@ -85,10 +84,6 @@
#include "rpl/rpl-private.h"
#endif
#if UIP_ND6_SEND_NS
#include "net/ipv6/uip-ds6-nbr.h"
#endif /* UIP_ND6_SEND_NS */
#include <string.h>
/*---------------------------------------------------------------------------*/
@ -895,7 +890,7 @@ ext_hdr_options_process(void)
*/
#if UIP_CONF_IPV6_RPL
PRINTF("Processing RPL option\n");
if(!rpl_verify_hbh_header(uip_ext_opt_offset)) {
if(rpl_verify_hbh_header(uip_ext_opt_offset)) {
PRINTF("RPL Option Error: Dropping Packet\n");
return 1;
}
@ -1155,13 +1150,6 @@ uip_process(uint8_t flag)
goto drop;
}
/* Refresh neighbor state after receiving a unicast message */
#if UIP_ND6_SEND_NS
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
uip_ds6_nbr_refresh_reachable_state(&UIP_IP_BUF->srcipaddr);
}
#endif /* UIP_ND6_SEND_NS */
#if UIP_CONF_ROUTER
/*
* Next header field processing. In IPv6, we can have extension headers,
@ -1240,6 +1228,14 @@ uip_process(uint8_t flag)
goto send;
}
#if UIP_CONF_IPV6_RPL
if(!rpl_update_header()) {
/* Packet can not be forwarded */
PRINTF("RPL header update error\n");
goto drop;
}
#endif /* UIP_CONF_IPV6_RPL */
UIP_IP_BUF->ttl = UIP_IP_BUF->ttl - 1;
PRINTF("Forwarding packet to ");
PRINT6ADDR(&UIP_IP_BUF->destipaddr);
@ -1586,6 +1582,10 @@ uip_process(uint8_t flag)
}
#endif /* UIP_UDP_CHECKSUMS */
#if UIP_CONF_IPV6_RPL
rpl_insert_header();
#endif /* UIP_CONF_IPV6_RPL */
UIP_STAT(++uip_stat.udp.sent);
goto ip_send_nolen;
#endif /* UIP_UDP */
@ -1854,10 +1854,8 @@ uip_process(uint8_t flag)
if((UIP_TCP_BUF->flags & TCP_SYN)) {
if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_RCVD) {
goto tcp_send_synack;
#if UIP_ACTIVE_OPEN
} else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) {
goto tcp_send_syn;
#endif
}
}
goto tcp_send_ack;

View file

@ -1,347 +0,0 @@
/*
* Copyright (c) 2014, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "websocket-http-client.h"
#include "net/ip/uiplib.h"
#include "net/ip/resolv.h"
#include "ip64-addr.h"
#include <stdio.h>
#include <string.h>
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
enum {
STATE_WAITING_FOR_HEADER,
STATE_WAITING_FOR_CONNECTED,
STATE_STEADY_STATE,
};
/*---------------------------------------------------------------------------*/
static void
send_get(struct websocket_http_client_state *s)
{
struct tcp_socket *tcps;
tcps = &s->s;
tcp_socket_send_str(tcps, "GET ");
tcp_socket_send_str(tcps, s->file);
tcp_socket_send_str(tcps, " HTTP/1.1\r\n");
tcp_socket_send_str(tcps, "Host: ");
tcp_socket_send_str(tcps, s->host);
tcp_socket_send_str(tcps, "\r\n");
if(strlen(s->header) > 0) {
tcp_socket_send_str(tcps, s->header);
}
/* The Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== header is
supposed to be a random value, encoded as base64, that is SHA1
hashed by the server and returned in a HTTP header. This is used
to make sure that we are not seeing some cached version of this
conversation. But we have no SHA1 code by default in Contiki, so
we can't check the return value. Therefore we just use a
hardcoded value here. */
tcp_socket_send_str(tcps,
"Connection: Upgrade\r\n"
"Upgrade: websocket\r\n"
"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Protocol:");
tcp_socket_send_str(tcps, s->subprotocol);
tcp_socket_send_str(tcps, "\r\n");
tcp_socket_send_str(tcps, "\r\n");
PRINTF("websocket-http-client: send_get(): output buffer left %d\n", tcp_socket_max_sendlen(tcps));
}
/*---------------------------------------------------------------------------*/
static void
send_connect(struct websocket_http_client_state *s)
{
struct tcp_socket *tcps;
char buf[20];
tcps = &s->s;
tcp_socket_send_str(tcps, "CONNECT ");
tcp_socket_send_str(tcps, s->host);
tcp_socket_send_str(tcps, ":");
sprintf(buf, "%d", s->port);
tcp_socket_send_str(tcps, buf);
tcp_socket_send_str(tcps, " HTTP/1.1\r\n");
tcp_socket_send_str(tcps, "Host: ");
tcp_socket_send_str(tcps, s->host);
tcp_socket_send_str(tcps, "\r\n");
tcp_socket_send_str(tcps, "Proxy-Connection: Keep-Alive\r\n\r\n");
}
/*---------------------------------------------------------------------------*/
static void
event(struct tcp_socket *tcps, void *ptr,
tcp_socket_event_t e)
{
struct websocket_http_client_state *s = ptr;
if(e == TCP_SOCKET_CONNECTED) {
if(s->proxy_port != 0) {
send_connect(s);
} else {
send_get(s);
}
} else if(e == TCP_SOCKET_CLOSED) {
websocket_http_client_closed(s);
} else if(e == TCP_SOCKET_TIMEDOUT) {
websocket_http_client_timedout(s);
} else if(e == TCP_SOCKET_ABORTED) {
websocket_http_client_aborted(s);
} else if(e == TCP_SOCKET_DATA_SENT) {
/* We could feed this information up to the websocket.c layer, but
we currently do not do that. */
}
}
/*---------------------------------------------------------------------------*/
static int
parse_header_byte(struct websocket_http_client_state *s,
uint8_t b)
{
static const char *endmarker = "\r\n\r\n";
PT_BEGIN(&s->parse_header_pt);
/* Skip the first part of the HTTP response */
while(b != ' ') {
PT_YIELD(&s->parse_header_pt);
}
/* Skip the space that follow the first part */
PT_YIELD(&s->parse_header_pt);
/* Read the first three bytes that constistute the HTTP status
code. We store the HTTP status code as an integer in the
s->http_status field. */
s->http_status = (b - '0');
PT_YIELD(&s->parse_header_pt);
s->http_status = s->http_status * 10 + (b - '0');
PT_YIELD(&s->parse_header_pt);
s->http_status = s->http_status * 10 + (b - '0');
if((s->proxy_port != 0 && !(s->http_status == 200 || s->http_status == 101)) ||
(s->proxy_port == 0 && s->http_status != 101)) {
/* This is a websocket request, so the server should have answered
with a 101 Switching protocols response. */
PRINTF("Websocket HTTP client didn't get the 101 status code (got %d), closing connection\n",
s->http_status);
websocket_http_client_close(s);
while(1) {
PT_YIELD(&s->parse_header_pt);
}
}
/* Keep eating header bytes until we reach the end of it. The end is
indicated by the string "\r\n\r\n". We don't actually look at any
of the headers.
The s->i variable contains the number of consecutive bytes
matched. If we match the total length of the string, we stop.
*/
s->i = 0;
do {
PT_YIELD(&s->parse_header_pt);
if(b == (uint8_t)endmarker[s->i]) {
s->i++;
} else {
s->i = 0;
}
} while(s->i < strlen(endmarker));
if(s->proxy_port != 0 && s->state == STATE_WAITING_FOR_HEADER) {
send_get(s);
s->state = STATE_WAITING_FOR_CONNECTED;
} else {
s->state = STATE_STEADY_STATE;
websocket_http_client_connected(s);
}
PT_END(&s->parse_header_pt);
}
/*---------------------------------------------------------------------------*/
static int
input(struct tcp_socket *tcps, void *ptr,
const uint8_t *inputptr, int inputdatalen)
{
struct websocket_http_client_state *s = ptr;
if(s->state == STATE_WAITING_FOR_HEADER ||
s->state == STATE_WAITING_FOR_CONNECTED) {
int i;
for(i = 0; i < inputdatalen; i++) {
parse_header_byte(s, inputptr[i]);
if(s->state == STATE_STEADY_STATE) {
i++;
break;
}
}
if(i < inputdatalen && s->state == STATE_STEADY_STATE) {
websocket_http_client_datahandler(s, &inputptr[i], inputdatalen - i);
}
} else {
websocket_http_client_datahandler(s, inputptr, inputdatalen);
}
return 0; /* all data consumed */
}
/*---------------------------------------------------------------------------*/
int
websocket_http_client_register(struct websocket_http_client_state *s,
const char *host,
uint16_t port,
const char *file,
const char *subprotocol,
const char *header)
{
if(host == NULL) {
return -1;
}
strncpy(s->host, host, sizeof(s->host));
if(file == NULL) {
return -1;
}
strncpy(s->file, file, sizeof(s->file));
if(subprotocol == NULL) {
return -1;
}
strncpy(s->subprotocol, subprotocol, sizeof(s->subprotocol));
if(header == NULL) {
strncpy(s->header, "", sizeof(s->header));
} else {
strncpy(s->header, header, sizeof(s->header));
}
if(port == 0) {
s->port = 80;
} else {
s->port = port;
}
return 1;
}
/*---------------------------------------------------------------------------*/
int
websocket_http_client_get(struct websocket_http_client_state *s)
{
uip_ip4addr_t ip4addr;
uip_ip6addr_t ip6addr;
uip_ip6addr_t *addr;
uint16_t port;
PRINTF("websocket_http_client_get: connecting to %s with file %s subprotocol %s header %s\n",
s->host, s->file, s->subprotocol, s->header);
s->state = STATE_WAITING_FOR_HEADER;
if(tcp_socket_register(&s->s, s,
s->inputbuf, sizeof(s->inputbuf),
s->outputbuf, sizeof(s->outputbuf),
input, event) < 0) {
return -1;
}
port = s->port;
if(s->proxy_port != 0) {
/* The proxy address should be an IPv6 address. */
uip_ipaddr_copy(&ip6addr, &s->proxy_addr);
port = s->proxy_port;
} else if(uiplib_ip6addrconv(s->host, &ip6addr) == 0) {
/* First check if the host is an IP address. */
if(uiplib_ip4addrconv(s->host, &ip4addr) != 0) {
ip64_addr_4to6(&ip4addr, &ip6addr);
} else {
/* Try to lookup the hostname. If it fails, we initiate a hostname
lookup. */
if(resolv_lookup(s->host, &addr) != RESOLV_STATUS_CACHED) {
return -1;
}
return tcp_socket_connect(&s->s, addr, s->port);
}
}
return tcp_socket_connect(&s->s, &ip6addr, port);
}
/*---------------------------------------------------------------------------*/
int
websocket_http_client_send(struct websocket_http_client_state *s,
const uint8_t *data,
uint16_t datalen)
{
if(s->state == STATE_STEADY_STATE) {
return tcp_socket_send(&s->s, data, datalen);
}
return -1;
}
/*---------------------------------------------------------------------------*/
int
websocket_http_client_sendbuflen(struct websocket_http_client_state *s)
{
return tcp_socket_max_sendlen(&s->s);
}
/*---------------------------------------------------------------------------*/
void
websocket_http_client_close(struct websocket_http_client_state *s)
{
tcp_socket_close(&s->s);
}
/*---------------------------------------------------------------------------*/
const char *
websocket_http_client_hostname(struct websocket_http_client_state *s)
{
return s->host;
}
/*---------------------------------------------------------------------------*/
void
websocket_http_client_init(struct websocket_http_client_state *s)
{
uip_create_unspecified(&s->proxy_addr);
s->proxy_port = 0;
}
/*---------------------------------------------------------------------------*/
void
websocket_http_client_set_proxy(struct websocket_http_client_state *s,
const uip_ipaddr_t *addr, uint16_t port)
{
uip_ipaddr_copy(&s->proxy_addr, addr);
s->proxy_port = port;
}
/*---------------------------------------------------------------------------*/
int
websocket_http_client_queuelen(struct websocket_http_client_state *s)
{
return tcp_socket_queuelen(&s->s);
}
/*---------------------------------------------------------------------------*/

View file

@ -1,123 +0,0 @@
/*
* Copyright (c) 2014, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKET_HTTP_CLIENT_H_
#define WEBSOCKET_HTTP_CLIENT_H_
#include "contiki.h"
#include "tcp-socket.h"
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_INPUTBUFSIZE
#define WEBSOCKET_HTTP_CLIENT_INPUTBUFSIZE WEBSOCKET_HTTP_CLIENT_CONF_INPUTBUFSIZE
#else /* WEBSOCKET_HTTP_CLIENT_CONF_INPUTBUFSIZE */
#define WEBSOCKET_HTTP_CLIENT_INPUTBUFSIZE 100
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_INPUTBUFSIZE */
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_OUTPUTBUFSIZE
#define WEBSOCKET_HTTP_CLIENT_OUTPUTBUFSIZE WEBSOCKET_HTTP_CLIENT_CONF_OUTPUTBUFSIZE
#else /* WEBSOCKET_HTTP_CLIENT_CONF_OUTPUTBUFSIZE */
#define WEBSOCKET_HTTP_CLIENT_OUTPUTBUFSIZE 300
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_OUTPUTBUFSIZE */
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_MAX_HOSTLEN
#define WEBSOCKET_HTTP_CLIENT_MAX_HOSTLEN WEBSOCKET_HTTP_CLIENT_CONF_MAX_HOSTLEN
#else /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_HOSTLEN */
#define WEBSOCKET_HTTP_CLIENT_MAX_HOSTLEN 32
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_HOSTLEN */
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_MAX_FILELEN
#define WEBSOCKET_HTTP_CLIENT_MAX_FILELEN WEBSOCKET_HTTP_CLIENT_CONF_MAX_FILELEN
#else /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_FILELEN */
#define WEBSOCKET_HTTP_CLIENT_MAX_FILELEN 32
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_FILELEN */
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_MAX_SUBPROTOCOLLEN
#define WEBSOCKET_HTTP_CLIENT_MAX_SUBPROTOCOLLEN WEBSOCKET_HTTP_CLIENT_CONF_MAX_SUBPROTOCOLLEN
#else /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_SUBPROTOCOLLEN */
#define WEBSOCKET_HTTP_CLIENT_MAX_SUBPROTOCOLLEN 24
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_SUBPROTOCOLLEN */
#ifdef WEBSOCKET_HTTP_CLIENT_CONF_MAX_HEADERLEN
#define WEBSOCKET_HTTP_CLIENT_MAX_HEADERLEN WEBSOCKET_HTTP_CLIENT_CONF_MAX_HEADERLEN
#else /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_HEADERLEN */
#define WEBSOCKET_HTTP_CLIENT_MAX_HEADERLEN 128
#endif /* WEBSOCKET_HTTP_CLIENT_CONF_MAX_HEADERLEN */
struct websocket_http_client_state {
struct tcp_socket s;
uint8_t inputbuf[WEBSOCKET_HTTP_CLIENT_INPUTBUFSIZE];
uint8_t outputbuf[WEBSOCKET_HTTP_CLIENT_OUTPUTBUFSIZE];
char host[WEBSOCKET_HTTP_CLIENT_MAX_HOSTLEN];
char file[WEBSOCKET_HTTP_CLIENT_MAX_FILELEN];
char subprotocol[WEBSOCKET_HTTP_CLIENT_MAX_SUBPROTOCOLLEN];
char header[WEBSOCKET_HTTP_CLIENT_MAX_HEADERLEN];
uint16_t port;
int state;
struct pt parse_header_pt;
int http_status;
int i;
uip_ipaddr_t proxy_addr;
uint16_t proxy_port;
};
void websocket_http_client_init(struct websocket_http_client_state *s);
void websocket_http_client_set_proxy(struct websocket_http_client_state *s,
const uip_ipaddr_t *addr, uint16_t port);
int websocket_http_client_register(struct websocket_http_client_state *s,
const char *host,
uint16_t port,
const char *file,
const char *subprotocol,
const char *hdr);
int websocket_http_client_get(struct websocket_http_client_state *s);
int websocket_http_client_send(struct websocket_http_client_state *s,
const uint8_t *data,
uint16_t datalen);
int websocket_http_client_sendbuflen(struct websocket_http_client_state *s);
void websocket_http_client_close(struct websocket_http_client_state *s);
const char *websocket_http_client_hostname(struct websocket_http_client_state *s);
int websocket_http_client_queuelen(struct websocket_http_client_state *s);
/* Callback functions that have to be implemented by the application
program. */
void websocket_http_client_datahandler(struct websocket_http_client_state *s,
const uint8_t *data, uint16_t len);
void websocket_http_client_connected(struct websocket_http_client_state *s);
void websocket_http_client_timedout(struct websocket_http_client_state *s);
void websocket_http_client_aborted(struct websocket_http_client_state *s);
void websocket_http_client_closed(struct websocket_http_client_state *s);
#endif /* WEBSOCKET_HTTP_CLIENT_H_ */

View file

@ -1,724 +0,0 @@
/*
* Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include "contiki-net.h"
#include "lib/petsciiconv.h"
#include "websocket.h"
PROCESS(websocket_process, "Websockets process");
#define MAX_HOSTLEN 64
#define MAX_PATHLEN 100
LIST(websocketlist);
#define WEBSOCKET_FIN_BIT 0x80
#define WEBSOCKET_OPCODE_MASK 0x0f
#define WEBSOCKET_OPCODE_CONT 0x00
#define WEBSOCKET_OPCODE_TEXT 0x01
#define WEBSOCKET_OPCODE_BIN 0x02
#define WEBSOCKET_OPCODE_CLOSE 0x08
#define WEBSOCKET_OPCODE_PING 0x09
#define WEBSOCKET_OPCODE_PONG 0x0a
#define WEBSOCKET_MASK_BIT 0x80
#define WEBSOCKET_LEN_MASK 0x7f
struct websocket_frame_hdr {
uint8_t opcode;
uint8_t len;
uint8_t extlen[4];
};
struct websocket_frame_mask {
uint8_t mask[4];
};
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/*---------------------------------------------------------------------------*/
static int
parse_url(const char *url, char *host, uint16_t *portptr, char *path)
{
const char *urlptr;
int i;
const char *file;
uint16_t port;
if(url == NULL) {
return 0;
}
/* Don't even try to go further if the URL is empty. */
if(strlen(url) == 0) {
return 0;
}
/* See if the URL starts with http:// or ws:// and remove it. */
if(strncmp(url, "http://", strlen("http://")) == 0) {
urlptr = url + strlen("http://");
} else if(strncmp(url, "ws://", strlen("ws://")) == 0) {
urlptr = url + strlen("ws://");
} else {
urlptr = url;
}
/* Find host part of the URL. */
for(i = 0; i < MAX_HOSTLEN; ++i) {
if(*urlptr == 0 ||
*urlptr == '/' ||
*urlptr == ' ' ||
*urlptr == ':') {
if(host != NULL) {
host[i] = 0;
}
break;
}
if(host != NULL) {
host[i] = *urlptr;
}
++urlptr;
}
/* Find the port. Default is 0, which lets the underlying transport
select its default port. */
port = 0;
if(*urlptr == ':') {
port = 0;
do {
++urlptr;
if(*urlptr >= '0' && *urlptr <= '9') {
port = (10 * port) + (*urlptr - '0');
}
} while(*urlptr >= '0' &&
*urlptr <= '9');
}
if(portptr != NULL) {
*portptr = port;
}
/* Find file part of the URL. */
while(*urlptr != '/' && *urlptr != 0) {
++urlptr;
}
if(*urlptr == '/') {
file = urlptr;
} else {
file = "/";
}
if(path != NULL) {
strncpy(path, file, MAX_PATHLEN);
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int
start_get(struct websocket *s)
{
if(websocket_http_client_get(&(s->s)) == 0) {
PRINTF("Out of memory error\n");
s->state = WEBSOCKET_STATE_CLOSED;
return WEBSOCKET_ERR;
} else {
PRINTF("Connecting...\n");
s->state = WEBSOCKET_STATE_HTTP_REQUEST_SENT;
return WEBSOCKET_OK;
}
return WEBSOCKET_ERR;
}
/*---------------------------------------------------------------------------*/
void
call(struct websocket *s, websocket_result_t r,
const uint8_t *data, uint16_t datalen)
{
if(s != NULL && s->callback != NULL) {
s->callback(s, r, data, datalen);
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(websocket_process, ev, data)
{
PROCESS_BEGIN();
while(1) {
PROCESS_WAIT_EVENT();
if(ev == resolv_event_found && data != NULL) {
int ret;
struct websocket *s;
const char *name = data;
/* Either found a hostname, or not. We need to go through the
list of websocketsand figure out to which connection this
reply corresponds, then either restart the HTTP get, or kill
it (if no hostname was found). */
for(s = list_head(websocketlist);
s != NULL;
s = list_item_next(s)) {
if(strcmp(name, websocket_http_client_hostname(&s->s)) == 0) {
ret = resolv_lookup(name, NULL);
if(ret == RESOLV_STATUS_CACHED) {
/* Hostname found, restart get. */
if(s->state == WEBSOCKET_STATE_DNS_REQUEST_SENT) {
PRINTF("Restarting get\n");
start_get(s);
}
} else {
if(s->state == WEBSOCKET_STATE_DNS_REQUEST_SENT) {
/* Hostname not found, kill connection. */
/* PRINTF("XXX killing connection\n");*/
call(s, WEBSOCKET_HOSTNAME_NOT_FOUND, NULL, 0);
}
}
}
}
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/* Callback function. Called from the webclient when the HTTP
* connection was abruptly aborted.
*/
void
websocket_http_client_aborted(struct websocket_http_client_state *client_state)
{
if(client_state != NULL) {
struct websocket *s = (struct websocket *)
((char *)client_state - offsetof(struct websocket, s));
PRINTF("Websocket reset\n");
s->state = WEBSOCKET_STATE_CLOSED;
call(s, WEBSOCKET_RESET, NULL, 0);
}
}
/*---------------------------------------------------------------------------*/
/* Callback function. Called from the webclient when the HTTP
* connection timed out.
*/
void
websocket_http_client_timedout(struct websocket_http_client_state *client_state)
{
if(client_state != NULL) {
struct websocket *s = (struct websocket *)
((char *)client_state - offsetof(struct websocket, s));
PRINTF("Websocket timed out\n");
s->state = WEBSOCKET_STATE_CLOSED;
call(s, WEBSOCKET_TIMEDOUT, NULL, 0);
}
}
/*---------------------------------------------------------------------------*/
/* Callback function. Called from the webclient when the HTTP
* connection was closed after a request from the "websocket_http_client_close()"
* function. .
*/
void
websocket_http_client_closed(struct websocket_http_client_state *client_state)
{
if(client_state != NULL) {
struct websocket *s = (struct websocket *)
((char *)client_state - offsetof(struct websocket, s));
PRINTF("Websocket closed.\n");
s->state = WEBSOCKET_STATE_CLOSED;
call(s, WEBSOCKET_CLOSED, NULL, 0);
}
}
/*---------------------------------------------------------------------------*/
/* Callback function. Called from the webclient when the HTTP
* connection is connected.
*/
void
websocket_http_client_connected(struct websocket_http_client_state *client_state)
{
struct websocket *s = (struct websocket *)
((char *)client_state - offsetof(struct websocket, s));
PRINTF("Websocket connected\n");
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
call(s, WEBSOCKET_CONNECTED, NULL, 0);
}
/*---------------------------------------------------------------------------*/
/* The websocket header may potentially be split into multiple TCP
segments. This function eats one byte each, puts it into
s->headercache, and checks whether or not the full header has been
received. */
static int
receive_header_byte(struct websocket *s, uint8_t byte)
{
int len;
int expected_len;
struct websocket_frame_hdr *hdr;
/* Take the next byte of data and place it in the header cache. */
if(s->state == WEBSOCKET_STATE_RECEIVING_HEADER) {
s->headercache[s->headercacheptr] = byte;
s->headercacheptr++;
if(s->headercacheptr >= sizeof(s->headercache)) {
/* Something bad happened: we ad read 10 bytes and had not yet
found a reasonable header, so we close the socket. */
websocket_close(s);
}
}
len = s->headercacheptr;
hdr = (struct websocket_frame_hdr *)s->headercache;
/* Check the header that we have received to see if it is long
enough. */
/* We start with expecting a length of at least two bytes (opcode +
1 length byte). */
expected_len = 2;
if(len >= expected_len) {
/* We check how many more bytes we should expect to see. The
length byte determines how many length bytes are included in
the header. */
if((hdr->len & WEBSOCKET_LEN_MASK) == 126) {
expected_len += 2;
} else if((hdr->len & WEBSOCKET_LEN_MASK) == 127) {
expected_len += 4;
}
/* If the option has the mask bit set, we should expect to see 4
mask bytes at the end of the header. */
if((hdr->len & WEBSOCKET_MASK_BIT ) != 0) {
expected_len += 4;
}
/* Now we know how long our header if expected to be. If it is
this long, we are done and we set the state to reflect this. */
if(len == expected_len) {
s->state = WEBSOCKET_STATE_HEADER_RECEIVED;
return 1;
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
/* Callback function. Called from the webclient module when HTTP data
* has arrived.
*/
void
websocket_http_client_datahandler(struct websocket_http_client_state *client_state,
const uint8_t *data, uint16_t datalen)
{
struct websocket *s = (struct websocket *)
((char *)client_state - offsetof(struct websocket, s));
struct websocket_frame_hdr *hdr;
struct websocket_frame_mask *maskptr;
if(data == NULL) {
call(s, WEBSOCKET_CLOSED, NULL, 0);
} else {
/* This function is a state machine that does different things
depending on the state. If we are waiting for header (the
default state), we change to the RECEIVING_HEADER state when we
get the first byte. If we are receiving header, we put all
bytes we have into a header buffer until the full header has
been received. If we have received the header, we parse it. If
we have received and parsed the header, we are ready to receive
data. Finally, if there is data left in the incoming packet, we
repeat the process. */
if(s->state == WEBSOCKET_STATE_WAITING_FOR_HEADER) {
s->state = WEBSOCKET_STATE_RECEIVING_HEADER;
s->headercacheptr = 0;
}
if(s->state == WEBSOCKET_STATE_RECEIVING_HEADER) {
while(datalen > 0 && s->state == WEBSOCKET_STATE_RECEIVING_HEADER) {
receive_header_byte(s, data[0]);
data++;
datalen--;
}
}
if(s->state == WEBSOCKET_STATE_HEADER_RECEIVED) {
/* If this is the start of an incoming websocket data frame, we
decode the header and check if we should act on in. If not, we
pipe the data to the application through a callback handler. If
data arrives in multiple packets, it is up to the application to
put it back together again. */
/* The websocket header is at the start of the incoming data. */
hdr = (struct websocket_frame_hdr *)s->headercache;
/* The s->left field holds the length of the application data
* chunk that we are about to receive. */
s->len = s->left = 0;
/* The s->mask field holds the bitmask of the data chunk, if
* any. */
memset(s->mask, 0, sizeof(s->mask));
/* We first read out the length of the application data
chunk. The length may be encoded over multiple bytes. If the
length is >= 126 bytes, it is encoded as two or more
bytes. The first length field determines if it is in 2 or 4
bytes. We also keep track of where the bitmask is held - its
place also differs depending on how the length is encoded. */
maskptr = (struct websocket_frame_mask *)hdr->extlen;
if((hdr->len & WEBSOCKET_LEN_MASK) < 126) {
s->len = s->left = hdr->len & WEBSOCKET_LEN_MASK;
} else if(hdr->len == 126) {
s->len = s->left = (hdr->extlen[0] << 8) + hdr->extlen[1];
maskptr = (struct websocket_frame_mask *)&hdr->extlen[2];
} else if(hdr->len == 127) {
s->len = s->left = ((uint32_t)hdr->extlen[0] << 24) +
((uint32_t)hdr->extlen[1] << 16) +
((uint32_t)hdr->extlen[2] << 8) +
hdr->extlen[3];
maskptr = (struct websocket_frame_mask *)&hdr->extlen[4];
}
/* Set user_data to point to the first byte of application data.
See if the application data chunk is masked or not. If it is,
we copy the bitmask into the s->mask field. */
if((hdr->len & WEBSOCKET_MASK_BIT) == 0) {
/* PRINTF("No mask\n");*/
} else {
memcpy(s->mask, &maskptr->mask, sizeof(s->mask));
/* PRINTF("There was a mask, %02x %02x %02x %02x\n",
s->mask[0], s->mask[1], s->mask[2], s->mask[3]);*/
}
/* Remember the opcode of the application chunk, put it in the
* s->opcode field. */
s->opcode = hdr->opcode & WEBSOCKET_OPCODE_MASK;
if(s->opcode == WEBSOCKET_OPCODE_PING) {
/* If the opcode is ping, we change the opcode to a pong, and
* send the data back. */
hdr->opcode = (hdr->opcode & (~WEBSOCKET_OPCODE_MASK)) |
WEBSOCKET_OPCODE_PONG;
websocket_http_client_send(&s->s, (const uint8_t*)hdr, 2);
if(s->left > 0) {
websocket_http_client_send(&s->s, (const uint8_t*)data, s->left);
}
PRINTF("Got ping\n");
call(s, WEBSOCKET_PINGED, NULL, 0);
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
} else if(s->opcode == WEBSOCKET_OPCODE_PONG) {
/* If the opcode is pong, we call the application to let it
know we got a pong. */
PRINTF("Got pong\n");
call(s, WEBSOCKET_PONG_RECEIVED, NULL, 0);
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
} else if(s->opcode == WEBSOCKET_OPCODE_CLOSE) {
/* If the opcode is a close, we send a close frame back. */
hdr->opcode = (hdr->opcode & (~WEBSOCKET_OPCODE_MASK)) |
WEBSOCKET_OPCODE_CLOSE;
websocket_http_client_send(&s->s, (const uint8_t*)hdr, 2);
if(s->left > 0) {
websocket_http_client_send(&s->s, (const uint8_t*)data, s->left);
}
PRINTF("websocket: got close, sending close\n");
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
websocket_http_client_close(&s->s);
} else if(s->opcode == WEBSOCKET_OPCODE_BIN ||
s->opcode == WEBSOCKET_OPCODE_TEXT) {
/* If the opcode is bin or text, and there is application
* layer data in the packet, we call the application to
* process it. */
if(s->left > 0) {
s->state = WEBSOCKET_STATE_RECEIVING_DATA;
if(datalen > 0) {
int len;
len = MIN(s->left, datalen);
/* XXX todo: mask if needed. */
call(s, WEBSOCKET_DATA, data, len);
data += len;
s->left -= len;
datalen -= len;
}
}
}
if(s->left == 0) {
call(s, WEBSOCKET_DATA_RECEIVED, NULL, s->len);
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
/* Need to keep parsing the incoming data to check for more
frames, if the incoming datalen is > than s->left. */
if(datalen > 0) {
PRINTF("XXX 1 again\n");
websocket_http_client_datahandler(client_state,
data, datalen);
}
}
} else if(s->state == WEBSOCKET_STATE_RECEIVING_DATA) {
/* XXX todo: mask if needed. */
/* PRINTF("Calling with s->left %d datalen %d\n",
s->left, datalen);*/
if(datalen > 0) {
if(datalen < s->left) {
call(s, WEBSOCKET_DATA, data, datalen);
s->left -= datalen;
data += datalen;
datalen = 0;
} else {
call(s, WEBSOCKET_DATA, data, s->left);
data += s->left;
datalen -= s->left;
s->left = 0;
}
}
if(s->left == 0) {
call(s, WEBSOCKET_DATA_RECEIVED, NULL, s->len);
s->state = WEBSOCKET_STATE_WAITING_FOR_HEADER;
/* Need to keep parsing the incoming data to check for more
frames, if the incoming datalen is > than len. */
if(datalen > 0) {
PRINTF("XXX 2 again (datalen %d s->left %d)\n", datalen, (int)s->left);
websocket_http_client_datahandler(client_state,
data, datalen);
}
}
}
}
}
/*---------------------------------------------------------------------------*/
static void
init(void)
{
static uint8_t inited = 0;
if(!inited) {
process_start(&websocket_process, NULL);
list_init(websocketlist);
inited = 1;
}
}
/*---------------------------------------------------------------------------*/
void
websocket_init(struct websocket *s)
{
init();
websocket_http_client_init(&s->s);
}
/*---------------------------------------------------------------------------*/
void
websocket_set_proxy(struct websocket *s,
const uip_ipaddr_t *addr, uint16_t port)
{
websocket_http_client_set_proxy(&s->s, addr, port);
}
/*---------------------------------------------------------------------------*/
websocket_result_t
websocket_open(struct websocket *s, const char *url,
const char *subprotocol, const char *hdr,
websocket_callback c)
{
int ret;
char host[MAX_HOSTLEN + 1] = {0};
char path[MAX_PATHLEN + 1] = {0};
uint16_t port;
uip_ipaddr_t addr;
init();
if(s == NULL) {
return WEBSOCKET_ERR;
}
if(s->state != WEBSOCKET_STATE_CLOSED) {
PRINTF("websocket_open: closing websocket before opening it again.\n");
websocket_close(s);
}
s->callback = c;
if(parse_url(url, host, &port, path)) {
list_add(websocketlist, s);
websocket_http_client_register(&s->s, host, port, path, subprotocol, hdr);
/* First check if the host is an IP address. */
if(uiplib_ip4addrconv(host, (uip_ip4addr_t *)&addr) == 0 &&
uiplib_ip6addrconv(host, (uip_ip6addr_t *)&addr) == 0) {
/* Try to lookup the hostname. If it fails, we initiate a hostname
lookup and print out an informative message on the
statusbar. */
ret = resolv_lookup(host, NULL);
if(ret != RESOLV_STATUS_CACHED) {
resolv_query(host);
s->state = WEBSOCKET_STATE_DNS_REQUEST_SENT;
PRINTF("Resolving host...\n");
return WEBSOCKET_OK;
}
}
PROCESS_CONTEXT_BEGIN(&websocket_process);
ret = start_get(s);
PROCESS_CONTEXT_END();
return ret;
}
return -1;
}
/*---------------------------------------------------------------------------*/
void
websocket_close(struct websocket *s)
{
websocket_http_client_close(&s->s);
s->state = WEBSOCKET_STATE_CLOSED;
}
/*---------------------------------------------------------------------------*/
static int
send_data(struct websocket *s, const void *data,
uint16_t datalen, uint8_t data_type_opcode)
{
uint8_t buf[WEBSOCKET_MAX_MSGLEN + 4 + 4]; /* The extra + 4 + 4 here
comes from the size of
the websocket framing
header. */
struct websocket_frame_hdr *hdr;
struct websocket_frame_mask *mask;
PRINTF("websocket send data len %d %.*s\n", datalen, datalen, (char *)data);
if(s->state == WEBSOCKET_STATE_CLOSED ||
s->state == WEBSOCKET_STATE_DNS_REQUEST_SENT ||
s->state == WEBSOCKET_STATE_HTTP_REQUEST_SENT) {
/* Trying to send data on a non-connected websocket. */
PRINTF("websocket send fail: not connected\n");
return -1;
}
/* We need to have 4 + 4 additional bytes for the websocket framing
header. */
if(4 + 4 + datalen > websocket_http_client_sendbuflen(&s->s)) {
PRINTF("websocket: too few bytes left (%d left, %d needed)\n",
websocket_http_client_sendbuflen(&s->s),
4 + 4 + datalen);
return -1;
}
if(datalen > sizeof(buf) - 4 - 4) {
PRINTF("websocket: trying to send too large data chunk %d > %d\n",
datalen, sizeof(buf) - 4 - 4);
return -1;
}
hdr = (struct websocket_frame_hdr *)&buf[0];
hdr->opcode = WEBSOCKET_FIN_BIT | data_type_opcode;
/* If the datalen is larger than 125 bytes, we need to send the data
length as two bytes. If the data length would be larger than 64k,
we should send the length as 4 bytes, but since we specify the
datalen as an unsigned 16-bit int, we do not handle the 64k case
here. */
if(datalen > 125) {
/* Data from client must always have the mask bit set, and a data
mask sent right after the header. */
hdr->len = 126 | WEBSOCKET_MASK_BIT;
hdr->extlen[0] = datalen >> 8;
hdr->extlen[1] = datalen & 0xff;
mask = (struct websocket_frame_mask *)&buf[4];
mask->mask[0] =
mask->mask[1] =
mask->mask[2] =
mask->mask[3] = 0;
memcpy(&buf[8], data, datalen);
return websocket_http_client_send(&s->s, buf, 8 + datalen);
} else {
/* Data from client must always have the mask bit set, and a data
mask sent right after the header. */
hdr->len = datalen | WEBSOCKET_MASK_BIT;
mask = (struct websocket_frame_mask *)&buf[2];
mask->mask[0] =
mask->mask[1] =
mask->mask[2] =
mask->mask[3] = 0;
memcpy(&buf[6], data, datalen);
return websocket_http_client_send(&s->s, buf, 6 + datalen);
}
return -1;
}
/*---------------------------------------------------------------------------*/
int
websocket_send_str(struct websocket *s, const char *str)
{
return send_data(s, str, strlen(str), WEBSOCKET_OPCODE_TEXT);
}
/*---------------------------------------------------------------------------*/
int
websocket_send(struct websocket *s, const uint8_t *data,
uint16_t datalen)
{
return send_data(s, data, datalen, WEBSOCKET_OPCODE_BIN);
}
/*---------------------------------------------------------------------------*/
int
websocket_ping(struct websocket *s)
{
uint8_t buf[sizeof(struct websocket_frame_hdr) +
sizeof(struct websocket_frame_mask)];
struct websocket_frame_hdr *hdr;
struct websocket_frame_mask *mask;
/* We need 2 + 4 additional bytes for the websocket framing
header. */
if(2 + 4 > websocket_http_client_sendbuflen(&s->s)) {
return -1;
}
hdr = (struct websocket_frame_hdr *)&buf[0];
mask = (struct websocket_frame_mask *)&buf[2];
hdr->opcode = WEBSOCKET_FIN_BIT | WEBSOCKET_OPCODE_PING;
/* Data from client must always have the mask bit set, and a data
mask sent right after the header. */
hdr->len = 0 | WEBSOCKET_MASK_BIT;
/* XXX: We just set a dummy mask of 0 for now and hope that this
works. */
mask->mask[0] =
mask->mask[1] =
mask->mask[2] =
mask->mask[3] = 0;
websocket_http_client_send(&s->s, buf, 2 + 4);
return 1;
}
/*---------------------------------------------------------------------------*/
int
websocket_queuelen(struct websocket *s)
{
return websocket_http_client_queuelen(&s->s);
}
/*---------------------------------------------------------------------------*/

View file

@ -1,113 +0,0 @@
/*
* Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKET_H
#define WEBSOCKET_H
#include "websocket-http-client.h"
typedef enum {
WEBSOCKET_ERR = 0,
WEBSOCKET_OK = 1,
WEBSOCKET_IN_PROGRESS = 2,
WEBSOCKET_HOSTNAME_NOT_FOUND = 3,
WEBSOCKET_CONNECTED = 4,
WEBSOCKET_DATA = 5,
WEBSOCKET_RESET = 6,
WEBSOCKET_TIMEDOUT = 7,
WEBSOCKET_CLOSED = 8,
WEBSOCKET_PINGED = 9,
WEBSOCKET_DATA_RECEIVED = 10,
WEBSOCKET_PONG_RECEIVED = 11,
} websocket_result_t;
struct websocket;
typedef void (* websocket_callback)(struct websocket *s,
websocket_result_t result,
const uint8_t *data,
uint16_t datalen);
#ifdef WEBSOCKET_CONF_MAX_MSGLEN
#define WEBSOCKET_MAX_MSGLEN WEBSOCKET_CONF_MAX_MSGLEN
#else /* WEBSOCKET_CONF_MAX_MSGLEN */
#define WEBSOCKET_MAX_MSGLEN 200
#endif /* WEBSOCKET_CONF_MAX_MSGLEN */
struct websocket {
struct websocket *next; /* Must be first. */
struct websocket_http_client_state s;
websocket_callback callback;
uint8_t mask[4];
uint32_t left, len;
uint8_t opcode;
uint8_t state;
uint8_t headercacheptr;
uint8_t headercache[10]; /* The maximum websocket header + mask is 6
+ 4 bytes long */
};
enum {
WEBSOCKET_STATE_CLOSED = 0,
WEBSOCKET_STATE_DNS_REQUEST_SENT = 1,
WEBSOCKET_STATE_HTTP_REQUEST_SENT = 2,
WEBSOCKET_STATE_WAITING_FOR_HEADER = 3,
WEBSOCKET_STATE_RECEIVING_HEADER = 4,
WEBSOCKET_STATE_HEADER_RECEIVED = 5,
WEBSOCKET_STATE_RECEIVING_DATA = 6,
};
void websocket_init(struct websocket *s);
void websocket_set_proxy(struct websocket *s,
const uip_ipaddr_t *addr, uint16_t port);
websocket_result_t websocket_open(struct websocket *s,
const char *url,
const char *subprotocol,
const char *hdr,
websocket_callback c);
int websocket_send(struct websocket *s,
const uint8_t *data, uint16_t datalen);
int websocket_send_str(struct websocket *s,
const char *strptr);
void websocket_close(struct websocket *s);
int websocket_ping(struct websocket *s);
int websocket_queuelen(struct websocket *s);
#endif /* WEBSOCKET_H */

View file

@ -51,7 +51,7 @@
/* Maximum value for the freshness counter */
#define FRESHNESS_MAX 16
/* Statistics with no update in FRESHNESS_EXPIRATION_TIMEOUT is not fresh */
#define FRESHNESS_EXPIRATION_TIME (10 * 60 * (clock_time_t)CLOCK_SECOND)
#define FRESHNESS_EXPIRATION_TIME (10 * 60 * CLOCK_SECOND)
/* EWMA (exponential moving average) used to maintain statistics over time */
#define EWMA_SCALE 100
@ -206,6 +206,6 @@ void
link_stats_init(void)
{
nbr_table_register(link_stats, NULL);
ctimer_set(&periodic_timer, 60 * (clock_time_t)CLOCK_SECOND * FRESHNESS_HALF_LIFE,
ctimer_set(&periodic_timer, 60 * CLOCK_SECOND * FRESHNESS_HALF_LIFE,
periodic, NULL);
}

View file

@ -52,9 +52,6 @@ const linkaddr_t linkaddr_null = { { 0, 0 } };
#if LINKADDR_SIZE == 8
const linkaddr_t linkaddr_null = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
#endif /*LINKADDR_SIZE == 8*/
#if LINKADDR_SIZE == 6
const linkaddr_t linkaddr_null = { { 0, 0, 0, 0, 0, 0 } };
#endif /*LINKADDR_SIZE == 6*/
#endif /*LINKADDR_SIZE == 2*/

View file

@ -207,13 +207,13 @@ static int we_are_receiving_burst = 0;
#define INTER_PACKET_INTERVAL RTIMER_ARCH_SECOND / 2500
#endif
/* AFTER_ACK_DETECTED_WAIT_TIME is the time to wait after a potential
/* AFTER_ACK_DETECTECT_WAIT_TIME is the time to wait after a potential
ACK packet has been detected until we can read it out from the
radio. */
#ifdef CONTIKIMAC_CONF_AFTER_ACK_DETECTED_WAIT_TIME
#define AFTER_ACK_DETECTED_WAIT_TIME CONTIKIMAC_CONF_AFTER_ACK_DETECTED_WAIT_TIME
#ifdef CONTIKIMAC_CONF_AFTER_ACK_DETECTECT_WAIT_TIME
#define AFTER_ACK_DETECTECT_WAIT_TIME CONTIKIMAC_CONF_AFTER_ACK_DETECTECT_WAIT_TIME
#else
#define AFTER_ACK_DETECTED_WAIT_TIME RTIMER_ARCH_SECOND / 1500
#define AFTER_ACK_DETECTECT_WAIT_TIME RTIMER_ARCH_SECOND / 1500
#endif
/* MAX_PHASE_STROBE_TIME is the time that we transmit repeated packets
@ -289,15 +289,9 @@ off(void)
}
}
/*---------------------------------------------------------------------------*/
static volatile rtimer_clock_t cycle_start;
static void powercycle_wrapper(struct rtimer *t, void *ptr);
static char powercycle(struct rtimer *t, void *ptr);
/*---------------------------------------------------------------------------*/
static volatile rtimer_clock_t cycle_start;
#if SYNC_CYCLE_STARTS
static volatile rtimer_clock_t sync_cycle_start;
static volatile uint8_t sync_cycle_phase;
#endif
/*---------------------------------------------------------------------------*/
static void
schedule_powercycle(struct rtimer *t, rtimer_clock_t time)
{
@ -346,7 +340,7 @@ powercycle_turn_radio_off(void)
#if CONTIKIMAC_CONF_COMPOWER
uint8_t was_on = radio_is_on;
#endif /* CONTIKIMAC_CONF_COMPOWER */
if(we_are_sending == 0 && we_are_receiving_burst == 0) {
off();
#if CONTIKIMAC_CONF_COMPOWER
@ -373,34 +367,13 @@ powercycle_wrapper(struct rtimer *t, void *ptr)
powercycle(t, ptr);
}
/*---------------------------------------------------------------------------*/
static void
advance_cycle_start(void)
{
#if SYNC_CYCLE_STARTS
/* Compute cycle start when RTIMER_ARCH_SECOND is not a multiple
of CHANNEL_CHECK_RATE */
if(sync_cycle_phase++ == NETSTACK_RDC_CHANNEL_CHECK_RATE) {
sync_cycle_phase = 0;
sync_cycle_start += RTIMER_ARCH_SECOND;
cycle_start = sync_cycle_start;
} else if( (RTIMER_ARCH_SECOND * NETSTACK_RDC_CHANNEL_CHECK_RATE) > 65535) {
uint32_t phase_time = sync_cycle_phase*RTIMER_ARCH_SECOND;
cycle_start = sync_cycle_start + phase_time/NETSTACK_RDC_CHANNEL_CHECK_RATE;
} else {
unsigned phase_time = sync_cycle_phase*RTIMER_ARCH_SECOND;
cycle_start = sync_cycle_start + phase_time/NETSTACK_RDC_CHANNEL_CHECK_RATE;
}
#endif
cycle_start += CYCLE_TIME;
}
/*---------------------------------------------------------------------------*/
static char
powercycle(struct rtimer *t, void *ptr)
{
#if SYNC_CYCLE_STARTS
static volatile rtimer_clock_t sync_cycle_start;
static volatile uint8_t sync_cycle_phase;
#endif
PT_BEGIN(&pt);
@ -414,6 +387,24 @@ powercycle(struct rtimer *t, void *ptr)
static uint8_t packet_seen;
static uint8_t count;
#if SYNC_CYCLE_STARTS
/* Compute cycle start when RTIMER_ARCH_SECOND is not a multiple
of CHANNEL_CHECK_RATE */
if(sync_cycle_phase++ == NETSTACK_RDC_CHANNEL_CHECK_RATE) {
sync_cycle_phase = 0;
sync_cycle_start += RTIMER_ARCH_SECOND;
cycle_start = sync_cycle_start;
} else {
#if (RTIMER_ARCH_SECOND * NETSTACK_RDC_CHANNEL_CHECK_RATE) > 65535
cycle_start = sync_cycle_start + ((unsigned long)(sync_cycle_phase*RTIMER_ARCH_SECOND))/NETSTACK_RDC_CHANNEL_CHECK_RATE;
#else
cycle_start = sync_cycle_start + (sync_cycle_phase*RTIMER_ARCH_SECOND)/NETSTACK_RDC_CHANNEL_CHECK_RATE;
#endif
}
#else
cycle_start += CYCLE_TIME;
#endif
packet_seen = 0;
for(count = 0; count < CCA_COUNT_MAX; ++count) {
@ -481,8 +472,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() ||
@ -494,26 +485,24 @@ powercycle(struct rtimer *t, void *ptr)
}
}
advance_cycle_start();
if(RTIMER_CLOCK_LT(RTIMER_NOW() , cycle_start - CHECK_TIME * 4)) {
if(RTIMER_CLOCK_LT(RTIMER_NOW() - cycle_start, CYCLE_TIME - CHECK_TIME * 4)) {
/* Schedule the next powercycle interrupt, or sleep the mcu
until then. Sleeping will not exit from this interrupt, so
ensure an occasional wake cycle or foreground processing will
be blocked until a packet is detected */
until then. Sleeping will not exit from this interrupt, so
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++ < mcusleepcycle) && !we_are_sending && !radio_is_on) {
rtimer_arch_sleep(CYCLE_TIME - (RTIMER_NOW() - cycle_start));
} else {
sleepcycle = 0;
#ifndef RDC_CONF_PT_YIELD_OFF
schedule_powercycle_fixed(t, cycle_start);
schedule_powercycle_fixed(t, CYCLE_TIME + cycle_start);
PT_YIELD(&pt);
#endif
}
#else
schedule_powercycle_fixed(t, cycle_start);
schedule_powercycle_fixed(t, CYCLE_TIME + cycle_start);
PT_YIELD(&pt);
#endif
}
@ -556,6 +545,9 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
int strobes;
uint8_t got_strobe_ack = 0;
uint8_t is_broadcast = 0;
#if WITH_PHASE_OPTIMIZATION
uint8_t is_known_receiver = 0;
#endif
uint8_t collisions;
int transmit_len;
int ret;
@ -564,13 +556,13 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
int len;
uint8_t seqno;
#endif
/* Exit if RDC and radio were explicitly turned off */
if(!contikimac_is_on && !contikimac_keep_radio_on) {
PRINTF("contikimac: radio is turned off\n");
return MAC_TX_ERR_FATAL;
}
if(packetbuf_totlen() == 0) {
PRINTF("contikimac: send_packet data len 0\n");
return MAC_TX_ERR_FATAL;
@ -612,10 +604,10 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
return MAC_TX_ERR_FATAL;
}
}
transmit_len = packetbuf_totlen();
NETSTACK_RADIO.prepare(packetbuf_hdrptr(), transmit_len);
if(!is_broadcast && !is_receiver_awake) {
#if WITH_PHASE_OPTIMIZATION
ret = phase_wait(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
@ -627,9 +619,9 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
if(ret != PHASE_UNKNOWN) {
is_known_receiver = 1;
}
#endif /* WITH_PHASE_OPTIMIZATION */
#endif /* WITH_PHASE_OPTIMIZATION */
}
/* By setting we_are_sending to one, we ensure that the rtimer
@ -647,7 +639,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
NETSTACK_RADIO.receiving_packet(), NETSTACK_RADIO.pending_packet());
return MAC_TX_COLLISION;
}
/* Switch off the radio to ensure that we didn't start sending while
the radio was doing a channel check. */
off();
@ -766,7 +758,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
NETSTACK_RADIO.channel_clear() == 0)) {
uint8_t ackbuf[ACK_LEN];
wt = RTIMER_NOW();
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTED_WAIT_TIME)) { }
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTECT_WAIT_TIME)) { }
len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
if(len == ACK_LEN && seqno == ackbuf[ACK_LEN - 1]) {
@ -855,7 +847,7 @@ qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
int ret;
int is_receiver_awake;
int pending;
if(buf_list == NULL) {
return;
}
@ -867,7 +859,7 @@ qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
mac_call_sent_callback(sent, ptr, MAC_TX_COLLISION, 1);
return;
}
/* Create and secure frames in advance */
curr = buf_list;
do {
@ -878,23 +870,19 @@ qsend_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
if(next != NULL) {
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, 1);
}
#if !NETSTACK_CONF_BRIDGE_MODE
/* If NETSTACK_CONF_BRIDGE_MODE is set, assume PACKETBUF_ADDR_SENDER is already set. */
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
#endif
packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
if(NETSTACK_FRAMER.create() < 0) {
PRINTF("contikimac: framer failed\n");
mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1);
return;
}
packetbuf_set_attr(PACKETBUF_ATTR_IS_CREATED_AND_SECURED, 1);
queuebuf_update_from_packetbuf(curr->buf);
}
curr = next;
} while(next != NULL);
/* The receiver needs to be awoken before we send */
is_receiver_awake = 0;
curr = buf_list;
@ -1082,7 +1070,7 @@ turn_off(int keep_radio_on)
}
}
/*---------------------------------------------------------------------------*/
static unsigned short
static clock_time_t
duty_cycle(void)
{
return (1ul * CLOCK_SECOND * CYCLE_TIME) / RTIMER_ARCH_SECOND;

View file

@ -231,12 +231,10 @@ tx_done(int status, struct rdc_buf_list *q, struct neighbor_queue *n)
mac_callback_t sent;
struct qbuf_metadata *metadata;
void *cptr;
uint8_t ntx;
metadata = (struct qbuf_metadata *)q->ptr;
sent = metadata->sent;
cptr = metadata->cptr;
ntx = n->transmissions;
switch(status) {
case MAC_TX_OK:
@ -253,7 +251,7 @@ tx_done(int status, struct rdc_buf_list *q, struct neighbor_queue *n)
}
free_packet(n, q, status);
mac_call_sent_callback(sent, cptr, status, ntx);
mac_call_sent_callback(sent, cptr, status, n->transmissions);
}
/*---------------------------------------------------------------------------*/
static void

View file

@ -918,7 +918,7 @@ turn_off(int keep_radio_on)
}
}
/*---------------------------------------------------------------------------*/
static unsigned short
static clock_time_t
channel_check_interval(void)
{
return (1ul * CLOCK_SECOND * DEFAULT_PERIOD) / RTIMER_ARCH_SECOND;

View file

@ -146,45 +146,36 @@ frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest
}
if(fcf->frame_version == FRAME802154_IEEE802154E_2012) {
/*
* IEEE 802.15.4-2015
* Table 7-2, PAN ID Compression value for frame version 0b10
*/
if((fcf->dest_addr_mode == FRAME802154_NOADDR &&
fcf->src_addr_mode == FRAME802154_NOADDR &&
fcf->panid_compression == 1) ||
(fcf->dest_addr_mode != FRAME802154_NOADDR &&
fcf->src_addr_mode == FRAME802154_NOADDR &&
fcf->panid_compression == 0) ||
(fcf->dest_addr_mode == FRAME802154_LONGADDRMODE &&
fcf->src_addr_mode == FRAME802154_LONGADDRMODE &&
fcf->panid_compression == 0) ||
((fcf->dest_addr_mode == FRAME802154_SHORTADDRMODE &&
fcf->src_addr_mode != FRAME802154_NOADDR) ||
(fcf->dest_addr_mode != FRAME802154_NOADDR &&
fcf->src_addr_mode == FRAME802154_SHORTADDRMODE)) ){
dest_pan_id = 1;
if(!fcf->panid_compression) {
/* Compressed PAN ID == no PAN ID at all */
if(fcf->dest_addr_mode == fcf->dest_addr_mode) {
/* No address or both addresses: include destination PAN ID */
dest_pan_id = 1;
} else if(fcf->dest_addr_mode) {
/* Only dest address, include dest PAN ID */
dest_pan_id = 1;
} else if(fcf->src_addr_mode) {
/* Only src address, include src PAN ID */
src_pan_id = 1;
}
}
if(fcf->panid_compression == 0 &&
((fcf->dest_addr_mode == FRAME802154_NOADDR &&
fcf->src_addr_mode == FRAME802154_LONGADDRMODE) ||
(fcf->dest_addr_mode == FRAME802154_NOADDR &&
fcf->src_addr_mode == FRAME802154_SHORTADDRMODE) ||
(fcf->dest_addr_mode == FRAME802154_SHORTADDRMODE &&
fcf->src_addr_mode == FRAME802154_SHORTADDRMODE) ||
(fcf->dest_addr_mode == FRAME802154_SHORTADDRMODE &&
fcf->src_addr_mode == FRAME802154_LONGADDRMODE) ||
(fcf->dest_addr_mode == FRAME802154_LONGADDRMODE &&
fcf->src_addr_mode == FRAME802154_SHORTADDRMODE))) {
src_pan_id = 1;
if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 1) {
/* No address included, include dest PAN ID conditionally */
if(!fcf->panid_compression) {
dest_pan_id = 1;
}
}
/* Remove the following rule the day rows 2 and 3 from table 2a are fixed: */
if(fcf->dest_addr_mode == 0 && fcf->dest_addr_mode == 0) {
/* Not meaningful, we include a PAN ID iff the compress flag is set, but
* this is what the standard currently stipulates */
dest_pan_id = fcf->panid_compression;
}
} else {
/* No PAN ID in ACK */
if(fcf->frame_type != FRAME802154_ACKFRAME) {
if(!fcf->panid_compression && (fcf->src_addr_mode & 3)) {
/* If compressed, don't include source PAN ID */
if(!fcf->panid_compression && fcf->src_addr_mode & 3) {
/* If compressed, don't inclue source PAN ID */
src_pan_id = 1;
}
if(fcf->dest_addr_mode & 3) {
@ -205,7 +196,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 +295,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 +353,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 +379,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 +451,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 +480,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

@ -70,7 +70,7 @@ struct ieee802154_ies {
uint16_t ie_mlme_len;
/* Payload Short MLME IEs */
uint8_t ie_tsch_synchronization_offset;
struct tsch_asn_t ie_asn;
struct asn_t ie_asn;
uint8_t ie_join_priority;
uint8_t ie_tsch_timeslot_id;
uint16_t ie_tsch_timeslot[tsch_ts_elements_count];

View file

@ -86,16 +86,14 @@ create_frame(int type, int do_create)
params.fcf.frame_pending = packetbuf_attr(PACKETBUF_ATTR_PENDING);
if(packetbuf_holds_broadcast()) {
params.fcf.ack_required = 0;
/* Suppress seqno on broadcast if supported (frame v2 or more) */
params.fcf.sequence_number_suppression = FRAME802154_VERSION >= FRAME802154_IEEE802154E_2012;
} else {
params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_MAC_ACK);
params.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO;
}
/* We do not compress PAN ID in outgoing frames, i.e. include one PAN ID (dest by default)
* There is one exception, seemingly a typo in Table 2a: rows 2 and 3: when there is no
* source nor destination address, we have dest PAN ID iff compression is *set*. */
params.fcf.panid_compression = 0;
params.fcf.sequence_number_suppression = FRAME802154_SUPPR_SEQNO;
/* Insert IEEE 802.15.4 version bits. */
params.fcf.frame_version = FRAME802154_VERSION;
@ -173,8 +171,7 @@ create_frame(int type, int do_create)
* Set up the source address using only the long address mode for
* phase 1.
*/
linkaddr_copy((linkaddr_t *)&params.src_addr,
packetbuf_addr(PACKETBUF_ADDR_SENDER));
linkaddr_copy((linkaddr_t *)&params.src_addr, &linkaddr_node_addr);
params.payload = packetbuf_dataptr();
params.payload_len = packetbuf_datalen();

View file

@ -51,16 +51,9 @@
struct seqno {
linkaddr_t sender;
clock_time_t timestamp;
uint8_t seqno;
};
#ifdef NETSTACK_CONF_MAC_SEQNO_MAX_AGE
#define SEQNO_MAX_AGE NETSTACK_CONF_MAC_SEQNO_MAX_AGE
#else /* NETSTACK_CONF_MAC_SEQNO_MAX_AGE */
#define SEQNO_MAX_AGE (20 * CLOCK_SECOND)
#endif /* NETSTACK_CONF_MAC_SEQNO_MAX_AGE */
#ifdef NETSTACK_CONF_MAC_SEQNO_HISTORY
#define MAX_SEQNOS NETSTACK_CONF_MAC_SEQNO_HISTORY
#else /* NETSTACK_CONF_MAC_SEQNO_HISTORY */
@ -73,7 +66,6 @@ int
mac_sequence_is_duplicate(void)
{
int i;
clock_time_t now = clock_time();
/*
* Check for duplicate packet by comparing the sequence number of the incoming
@ -83,14 +75,8 @@ mac_sequence_is_duplicate(void)
if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
&received_seqnos[i].sender)) {
if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) == received_seqnos[i].seqno) {
#if SEQNO_MAX_AGE > 0
if(now - received_seqnos[i].timestamp <= SEQNO_MAX_AGE) {
/* Duplicate packet. */
return 1;
}
#else /* SEQNO_MAX_AGE > 0 */
/* Duplicate packet. */
return 1;
#endif /* SEQNO_MAX_AGE > 0 */
}
break;
}
@ -117,7 +103,6 @@ mac_sequence_register_seqno(void)
memcpy(&received_seqnos[j], &received_seqnos[j - 1], sizeof(struct seqno));
}
received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
received_seqnos[0].timestamp = clock_time();
linkaddr_copy(&received_seqnos[0].sender,
packetbuf_addr(PACKETBUF_ADDR_SENDER));
}

View file

@ -70,7 +70,7 @@ off(int keep_radio_on)
return 0;
}
/*---------------------------------------------------------------------------*/
static unsigned short
static clock_time_t
channel_check_interval(void)
{
return 0;

View file

@ -87,7 +87,7 @@ off(int keep_radio_on)
}
}
/*---------------------------------------------------------------------------*/
static unsigned short
static clock_time_t
channel_check_interval(void)
{
return 0;

View file

@ -46,10 +46,10 @@
#include "net/rime/rimestats.h"
#include <string.h>
#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64
#if CONTIKI_TARGET_COOJA
#include "lib/simEnvChange.h"
#include "sys/cooja_mt.h"
#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */
#endif /* CONTIKI_TARGET_COOJA */
#define DEBUG 0
#if DEBUG
@ -158,10 +158,10 @@ send_one_packet(mac_callback_t sent, void *ptr)
wt = RTIMER_NOW();
watchdog_periodic();
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) {
#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64
#if CONTIKI_TARGET_COOJA
simProcessRunValue = 1;
cooja_mt_yield();
#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */
#endif /* CONTIKI_TARGET_COOJA */
}
ret = MAC_TX_NOACK;
@ -176,10 +176,10 @@ send_one_packet(mac_callback_t sent, void *ptr)
watchdog_periodic();
while(RTIMER_CLOCK_LT(RTIMER_NOW(),
wt + AFTER_ACK_DETECTED_WAIT_TIME)) {
#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64
simProcessRunValue = 1;
cooja_mt_yield();
#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */
#if CONTIKI_TARGET_COOJA
simProcessRunValue = 1;
cooja_mt_yield();
#endif /* CONTIKI_TARGET_COOJA */
}
}
@ -195,8 +195,8 @@ send_one_packet(mac_callback_t sent, void *ptr)
}
}
} else {
PRINTF("nullrdc tx noack\n");
}
PRINTF("nullrdc tx noack\n");
}
}
break;
case RADIO_TX_COLLISION:
@ -303,7 +303,7 @@ packet_input(void)
}
#endif /* RDC_WITH_DUPLICATE_DETECTION */
#endif /* NULLRDC_802154_AUTOACK */
#if NULLRDC_SEND_802154_ACK
{
frame802154_t info154;
@ -343,7 +343,7 @@ off(int keep_radio_on)
}
}
/*---------------------------------------------------------------------------*/
static unsigned short
static clock_time_t
channel_check_interval(void)
{
return 0;

View file

@ -87,7 +87,7 @@ struct rdc_driver {
int (* off)(int keep_radio_on);
/** Returns the channel check interval, expressed in clock_time_t ticks. */
unsigned short (* channel_check_interval)(void);
clock_time_t (* channel_check_interval)(void);
};
#endif /* RDC_H_ */

View file

@ -251,7 +251,7 @@ init(void)
NETSTACK_RADIO.on();
}
/*---------------------------------------------------------------------------*/
static unsigned short
static clock_time_t
channel_check_interval(void)
{
return 0;

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",
@ -11,11 +11,8 @@ which defines how to run a basic RPL+TSCH network.
It was developped by:
* Simon Duquennoy, SICS, simonduq@sics.se, github user: [simonduq](https://github.com/simonduq)
* 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,12 +26,11 @@ 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
* Orchestra: an autonomous scheduler for TSCH+RPL networks
* A drift compensation mechanism
It has been tested on the following platforms:
* NXP JN516x (`jn516x`, tested on hardware)
@ -42,9 +38,7 @@ It has been tested on the following platforms:
* Zolertia Z1 (`z1`, tested in cooja only)
* CC2538DK (`cc2538dk`, tested on hardware)
* Zolertia Zoul (`zoul`, tested on hardware)
* OpenMote-CC2538 (`openmote-cc2538`, tested on hardware)
* CC2650 (`srf06-cc26xx`, tested on hardware)
* Cooja mote (`cooja`, tested with cooja)
This implementation was present at the ETSI Plugtest
event in Prague in July 2015, and did successfully inter-operate with all
@ -77,7 +71,6 @@ Implements the 6TiSCH minimal configuration K1-K2 keys pair.
* `tsch-rpl.[ch]`: used for TSCH+RPL networks, to align TSCH and RPL states (preferred parent -> time source,
rank -> join priority) as defined in the 6TiSCH minimal configuration.
* `tsch-log.[ch]`: logging system for TSCH, including delayed messages for logging from slot operation interrupt.
* `tsch-adaptive-timesync.c`: used to learn the relative drift to the node's time source and automatically compensate for it.
Orchestra is implemented in:
* `apps/orchestra`: see `apps/orchestra/README.md` for more information.
@ -86,7 +79,7 @@ Orchestra is implemented in:
A simple TSCH+RPL example is included under `examples/ipv6/rpl-tsch`.
To use TSCH, first make sure your platform supports it.
Currently, `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul`, `openmote-cc2538`, `srf06-cc26xx`, and `cooja` are the supported platforms.
Currently, `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul` and `srf06-cc26xx` are the supported platforms.
To add your own, we refer the reader to the next section.
To add TSCH to your application, first include the TSCH module from your makefile with:
@ -172,7 +165,7 @@ Finally, one can also implement his own scheduler, centralized or distributed, b
## Porting TSCH to a new platform
Porting TSCH to a new platform requires a few new features in the radio driver, a number of timing-related configuration paramters.
The easiest is probably to start from one of the existing port: `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul`, `openmote-cc2538`, `srf06-cc26xx`.
The easiest is probably to start from one of the existing port: `jn516x`, `sky`, `z1`, `cc2538dk`, `zoul`, `srf06-cc26xx`.
### Radio features required for TSCH
@ -182,7 +175,7 @@ Instead, TSCH will poll the driver for incoming packets, from interrupt, exactly
TSCH will check when initializing (in `tsch_init`) that the radio driver supports all required features, namely:
* get and set Rx mode (`RADIO_PARAM_RX_MODE`) as follows:
* disable address filtering with `RADIO_RX_MODE_ADDRESS_FILTER`
* enable address filtering with `RADIO_RX_MODE_ADDRESS_FILTER`
* disable auto-ack with `RADIO_RX_MODE_AUTOACK`
* enable poll mode with `RADIO_RX_MODE_POLL_MODE`
* get and set Tx mode (`RADIO_PARAM_TX_MODE`) as follows:
@ -206,8 +199,6 @@ too slow for the default 10ms timeslots.
1. [IEEE 802.15.4e-2012 ammendment][ieee802.15.4e-2012]
2. [IETF 6TiSCH Working Group][ietf-6tisch-wg]
3. [A test procedure for Contiki timers in TSCH][tsch-sync-test]
[ieee802.15.4e-2012]: http://standards.ieee.org/getieee802/download/802.15.4e-2012.pdf
[ietf-6tisch-wg]: https://datatracker.ietf.org/wg/6tisch
[tsch-sync-test]: https://github.com/abbypjoby/Contiki-Synchronisation-Test

View file

@ -38,10 +38,8 @@
*
*/
#include "net/mac/tsch/tsch.h"
#include "net/mac/tsch/tsch-conf.h"
#include "net/mac/tsch/tsch-adaptive-timesync.h"
#include "net/mac/tsch/tsch-log.h"
#include "tsch-adaptive-timesync.h"
#include "tsch-log.h"
#include <stdio.h>
#if TSCH_ADAPTIVE_TIMESYNC
@ -74,10 +72,6 @@ timesync_entry_add(int32_t val, uint32_t time_delta)
buffer[pos] = val;
if(timesync_entry_count < NUM_TIMESYNC_ENTRIES) {
timesync_entry_count++;
} else {
/* We now have accurate drift compensation.
* Increase keep-alive timeout. */
tsch_set_ka_timeout(TSCH_MAX_KEEPALIVE_TIMEOUT);
}
pos = (pos + 1) % NUM_TIMESYNC_ENTRIES;

View file

@ -44,13 +44,13 @@
/************ Types ***********/
/* The ASN is an absolute slot number over 5 bytes. */
struct tsch_asn_t {
struct asn_t {
uint32_t ls4b; /* least significant 4 bytes */
uint8_t ms1b; /* most significant 1 byte */
};
/* For quick modulo operation on ASN */
struct tsch_asn_divisor_t {
struct asn_divisor_t {
uint16_t val; /* Divisor value */
uint16_t asn_ms1b_remainder; /* Remainder of the operation 0x100000000 / val */
};
@ -58,38 +58,38 @@ struct tsch_asn_divisor_t {
/************ Macros **********/
/* Initialize ASN */
#define TSCH_ASN_INIT(asn, ms1b_, ls4b_) do { \
#define ASN_INIT(asn, ms1b_, ls4b_) do { \
(asn).ms1b = (ms1b_); \
(asn).ls4b = (ls4b_); \
} while(0);
/* Increment an ASN by inc (32 bits) */
#define TSCH_ASN_INC(asn, inc) do { \
#define ASN_INC(asn, inc) do { \
uint32_t new_ls4b = (asn).ls4b + (inc); \
if(new_ls4b < (asn).ls4b) { (asn).ms1b++; } \
(asn).ls4b = new_ls4b; \
} while(0);
/* Decrement an ASN by inc (32 bits) */
#define TSCH_ASN_DEC(asn, dec) do { \
#define ASN_DEC(asn, dec) do { \
uint32_t new_ls4b = (asn).ls4b - (dec); \
if(new_ls4b > (asn).ls4b) { (asn).ms1b--; } \
(asn).ls4b = new_ls4b; \
} while(0);
/* Returns the 32-bit diff between asn1 and asn2 */
#define TSCH_ASN_DIFF(asn1, asn2) \
#define ASN_DIFF(asn1, asn2) \
((asn1).ls4b - (asn2).ls4b)
/* Initialize a struct asn_divisor_t */
#define TSCH_ASN_DIVISOR_INIT(div, val_) do { \
#define ASN_DIVISOR_INIT(div, val_) do { \
(div).val = (val_); \
(div).asn_ms1b_remainder = ((0xffffffff % (val_)) + 1) % (val_); \
} while(0);
/* Returns the result (16 bits) of a modulo operation on ASN,
* with divisor being a struct asn_divisor_t */
#define TSCH_ASN_MOD(asn, div) \
#define ASN_MOD(asn, div) \
((uint16_t)((asn).ls4b % (div).val) \
+ (uint16_t)((asn).ms1b * (div).asn_ms1b_remainder % (div).val)) \
% (div).val

View file

@ -174,7 +174,7 @@
#ifdef TSCH_CONF_ADAPTIVE_TIMESYNC
#define TSCH_ADAPTIVE_TIMESYNC TSCH_CONF_ADAPTIVE_TIMESYNC
#else
#define TSCH_ADAPTIVE_TIMESYNC 1
#define TSCH_ADAPTIVE_TIMESYNC 0
#endif
/* HW frame filtering enabled */

View file

@ -132,7 +132,7 @@ tsch_log_prepare_add(void)
int log_index = ringbufindex_peek_put(&log_ringbuf);
if(log_index != -1) {
struct tsch_log_t *log = &log_array[log_index];
log->asn = tsch_current_asn;
log->asn = current_asn;
log->link = current_link;
return log;
} else {

View file

@ -81,7 +81,7 @@ struct tsch_log_t {
tsch_log_rx,
tsch_log_message
} type;
struct tsch_asn_t asn;
struct asn_t asn;
struct tsch_link *link;
union {
char message[48];

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